From 8cfc3bd5b27538a88906475f7d301a99bc655c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Fri, 17 Apr 2026 13:11:36 +0200 Subject: [PATCH 01/20] add entrypoint factory --- config/services.yml | 3 + src/Entrypoints/Entrypoint.php | 28 ++++++++ src/Entrypoints/EntrypointBuilderFactory.php | 17 +++++ src/Entrypoints/Entrypoints.php | 29 ++++++++ src/Entrypoints/EntrypointsBuilder.php | 76 ++++++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 src/Entrypoints/Entrypoint.php create mode 100644 src/Entrypoints/EntrypointBuilderFactory.php create mode 100644 src/Entrypoints/Entrypoints.php create mode 100644 src/Entrypoints/EntrypointsBuilder.php diff --git a/config/services.yml b/config/services.yml index d418eaf..d2ec534 100644 --- a/config/services.yml +++ b/config/services.yml @@ -6,6 +6,7 @@ services: $webDir: '%contao.web_dir%' $encoreCache: '@webpack_encore.cache' Psr\Cache\CacheItemPoolInterface: "@webpack_encore.cache" + Symfony\WebpackEncoreBundle\Asset\TagRenderer: '@webpack_encore.tag_renderer' HeimrichHannot\EncoreBundle\: resource: "../src/{Asset,Collection,Command,DataContainer,EventListener,Helper}/*" @@ -13,6 +14,8 @@ services: public: true autoconfigure: true + HeimrichHannot\EncoreBundle\Entrypoints\EntrypointBuilderFactory: ~ + huh.encore.asset.frontend: alias: HeimrichHannot\EncoreBundle\Asset\FrontendAsset public: true diff --git a/src/Entrypoints/Entrypoint.php b/src/Entrypoints/Entrypoint.php new file mode 100644 index 0000000..9c1ad31 --- /dev/null +++ b/src/Entrypoints/Entrypoint.php @@ -0,0 +1,28 @@ +utils); + } +} \ No newline at end of file diff --git a/src/Entrypoints/Entrypoints.php b/src/Entrypoints/Entrypoints.php new file mode 100644 index 0000000..cd36b8d --- /dev/null +++ b/src/Entrypoints/Entrypoints.php @@ -0,0 +1,29 @@ +entrypoints[$entrypoint->name] = $entrypoint; + if ($entrypoint->active) { + $this->active[$entrypoint->name] = $entrypoint; + } else { + unset($this->active[$entrypoint->name]); + } + } + + public function all(): array + { + return $this->entrypoints; + } + + public function allActive(): array + { + return $this->active; + } +} \ No newline at end of file diff --git a/src/Entrypoints/EntrypointsBuilder.php b/src/Entrypoints/EntrypointsBuilder.php new file mode 100644 index 0000000..7e861a1 --- /dev/null +++ b/src/Entrypoints/EntrypointsBuilder.php @@ -0,0 +1,76 @@ +pageModel = $page; + $this->pageField = $field; + return $this; + } + + public function setLayout(LayoutModel $layout, string $field = EncoreEntriesSelectField::NAME_DEFAULT): self + { + $this->layout = $layout; + $this->layoutField = $field; + return $this; + } + + public function build(): Entrypoints + { + $entrypoints = new Entrypoints(); + + foreach ($this->frontendAsset->getActiveEntrypoints() as $entrypoint) { + $entrypoints->add(Entrypoint::fromString($entrypoint)); + } + + if ($this->pageModel && !$this->layout) { + $this->pageModel->loadDetails(); + $layout = LayoutModel::findByPk($this->pageModel->layout); + if ($layout) { + $this->setLayout($layout); + } + } + + if ($this->layout) { + foreach (StringUtil::deserialize($this->layout->{$this->layoutField}, true) as $entrypoint) { + $entrypoints->add(Entrypoint::fromArray($entrypoint)); + } + } + + if (null !== $this->pageModel) { + $pages = $this->utils->model()->findParentsRecursively($this->pageModel, 'pid'); + $pages[] = $this->pageModel; + + foreach ($pages as $page) { + foreach (StringUtil::deserialize($page->{$this->pageField}, true) as $entrypoint) { + if (!isset($entrypoint['name'])) { + continue; + } + $entrypoints->add(Entrypoint::fromArray($entrypoint)); + } + } + } + + return $entrypoints; + } +} \ No newline at end of file From 35e304da89cb1e3b8cd4d29aad6fd8409d05bf72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Fri, 17 Apr 2026 13:12:42 +0200 Subject: [PATCH 02/20] add default name constant --- contao/dca/tl_layout.php | 2 +- src/Dca/EncoreEntriesSelectField.php | 2 ++ src/Dca/EncoreEntriesSelectFieldOptions.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/contao/dca/tl_layout.php b/contao/dca/tl_layout.php index b50a07b..24eb008 100644 --- a/contao/dca/tl_layout.php +++ b/contao/dca/tl_layout.php @@ -27,7 +27,7 @@ /* * Subpalettes */ -$dca['subpalettes']['addEncore'] = 'encoreEntries,encoreStylesheetsImportsTemplate,encoreScriptsImportsTemplate'; +$dca['subpalettes']['addEncore'] = EncoreEntriesSelectField::NAME_DEFAULT.',encoreStylesheetsImportsTemplate,encoreScriptsImportsTemplate'; /** * Fields. diff --git a/src/Dca/EncoreEntriesSelectField.php b/src/Dca/EncoreEntriesSelectField.php index ea4b1ad..721a2fd 100644 --- a/src/Dca/EncoreEntriesSelectField.php +++ b/src/Dca/EncoreEntriesSelectField.php @@ -4,6 +4,8 @@ class EncoreEntriesSelectField { + public const NAME_DEFAULT = 'encoreEntries'; + protected static array $tables = []; /** diff --git a/src/Dca/EncoreEntriesSelectFieldOptions.php b/src/Dca/EncoreEntriesSelectFieldOptions.php index 2abfa75..091df03 100644 --- a/src/Dca/EncoreEntriesSelectFieldOptions.php +++ b/src/Dca/EncoreEntriesSelectFieldOptions.php @@ -4,7 +4,7 @@ class EncoreEntriesSelectFieldOptions { - protected string $fieldName = 'encoreEntries'; + protected string $fieldName = EncoreEntriesSelectField::NAME_DEFAULT; protected bool $includeActiveCheckbox = false; protected ?array $fieldLabel = null; protected ?array $selectLabel = null; From 5fb8364f205975ace39b4b4fb1e0bdc76446a634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Fri, 17 Apr 2026 13:55:22 +0200 Subject: [PATCH 03/20] extend entrypoints --- src/Entrypoints/Entrypoint.php | 9 +---- src/Entrypoints/EntrypointBuilderFactory.php | 10 ++++- src/Entrypoints/Entrypoints.php | 14 ++++++- src/Entrypoints/EntrypointsBuilder.php | 39 +++++++++++++++++--- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/Entrypoints/Entrypoint.php b/src/Entrypoints/Entrypoint.php index 9c1ad31..a7fb5e7 100644 --- a/src/Entrypoints/Entrypoint.php +++ b/src/Entrypoints/Entrypoint.php @@ -11,18 +11,13 @@ public function __construct( public readonly bool $requiresCss = false, ) {} - public static function fromArray(array $config): Entrypoint + public static function fromArray(array $config, bool $active = true): Entrypoint { return new self( name: $config['name'], - active: (bool)$config['active'] ?? true, + active: $active, head: (bool)$config['head'] ?? true, requiresCss: (bool)$config['requiresCss'] ?? true, ); } - - public static function fromString(string $name): Entrypoint - { - return new self(name: $name); - } } \ No newline at end of file diff --git a/src/Entrypoints/EntrypointBuilderFactory.php b/src/Entrypoints/EntrypointBuilderFactory.php index 4f20292..f09a92e 100644 --- a/src/Entrypoints/EntrypointBuilderFactory.php +++ b/src/Entrypoints/EntrypointBuilderFactory.php @@ -2,16 +2,24 @@ namespace HeimrichHannot\EncoreBundle\Entrypoints; +use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; +use HeimrichHannot\EncoreBundle\Collection\EntryCollection; use HeimrichHannot\UtilsBundle\Util\Utils; class EntrypointBuilderFactory { public function __construct( private readonly Utils $utils, + private readonly FrontendAsset $frontendAsset, + private readonly EntryCollection $entryCollection, ) {} public function create(): EntrypointsBuilder { - return new EntrypointsBuilder($this->utils); + return new EntrypointsBuilder( + $this->utils, + $this->frontendAsset, + $this->entryCollection, + ); } } \ No newline at end of file diff --git a/src/Entrypoints/Entrypoints.php b/src/Entrypoints/Entrypoints.php index cd36b8d..7bbf59c 100644 --- a/src/Entrypoints/Entrypoints.php +++ b/src/Entrypoints/Entrypoints.php @@ -4,8 +4,14 @@ class Entrypoints { + /** + * @var Entrypoint[] + */ private array $entrypoints = []; - private array $active; + /** + * @var Entrypoint[] + */ + private array $active = []; public function add(Entrypoint $entrypoint) { @@ -17,11 +23,17 @@ public function add(Entrypoint $entrypoint) } } + /** + * @return Entrypoint[] + */ public function all(): array { return $this->entrypoints; } + /** + * @return Entrypoint[] + */ public function allActive(): array { return $this->active; diff --git a/src/Entrypoints/EntrypointsBuilder.php b/src/Entrypoints/EntrypointsBuilder.php index 7e861a1..095989f 100644 --- a/src/Entrypoints/EntrypointsBuilder.php +++ b/src/Entrypoints/EntrypointsBuilder.php @@ -6,6 +6,7 @@ use Contao\PageModel; use Contao\StringUtil; use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; +use HeimrichHannot\EncoreBundle\Collection\EntryCollection; use HeimrichHannot\EncoreBundle\Dca\EncoreEntriesSelectField; use HeimrichHannot\UtilsBundle\Util\Utils; @@ -15,10 +16,12 @@ class EntrypointsBuilder private string $pageField = ''; private ?LayoutModel $layout = null; private string $layoutField = ''; + private array $available = []; public function __construct( private readonly Utils $utils, private readonly FrontendAsset $frontendAsset, + private readonly EntryCollection $entryCollection, ) {} public function setPage(PageModel $page, string $field = EncoreEntriesSelectField::NAME_DEFAULT): self @@ -38,9 +41,15 @@ public function setLayout(LayoutModel $layout, string $field = EncoreEntriesSele public function build(): Entrypoints { $entrypoints = new Entrypoints(); + $available = $this->entryCollection->getEntries(); + $available = array_combine(array_column($available, 'name'), $available); + $this->available = $available; foreach ($this->frontendAsset->getActiveEntrypoints() as $entrypoint) { - $entrypoints->add(Entrypoint::fromString($entrypoint)); + $this->addEntrypoint( + entrypoints: $entrypoints, + name: $entrypoint, + ); } if ($this->pageModel && !$this->layout) { @@ -53,7 +62,11 @@ public function build(): Entrypoints if ($this->layout) { foreach (StringUtil::deserialize($this->layout->{$this->layoutField}, true) as $entrypoint) { - $entrypoints->add(Entrypoint::fromArray($entrypoint)); + $this->addEntrypoint( + entrypoints: $entrypoints, + name: $entrypoint['name'] ?? '', + active: (bool)($entrypoint['active'] ?? true) + ); } } @@ -63,14 +76,28 @@ public function build(): Entrypoints foreach ($pages as $page) { foreach (StringUtil::deserialize($page->{$this->pageField}, true) as $entrypoint) { - if (!isset($entrypoint['name'])) { - continue; - } - $entrypoints->add(Entrypoint::fromArray($entrypoint)); + $this->addEntrypoint( + entrypoints: $entrypoints, + name: $entrypoint['name'] ?? '', + active: (bool)($entrypoint['active'] ?? true) + ); } } } return $entrypoints; } + + private function addEntrypoint(Entrypoints $entrypoints, string $name, bool $active = true): void + { + if ('' === $name) { + return; + } + + if (!isset($this->available[$name])) { + return; + } + + $entrypoints->add(Entrypoint::fromArray($this->available[$name], $active)); + } } \ No newline at end of file From b054c1741d966d2c20ee2e03a0d78acc83ff0c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Fri, 17 Apr 2026 13:55:29 +0200 Subject: [PATCH 04/20] current working state --- .../InjectPageEntrypointsListener.php | 61 +++++++++++++++++++ src/Routing/ResponseContext/EntrypointBag.php | 21 +++++++ 2 files changed, 82 insertions(+) create mode 100644 src/EventListener/InjectPageEntrypointsListener.php create mode 100644 src/Routing/ResponseContext/EntrypointBag.php diff --git a/src/EventListener/InjectPageEntrypointsListener.php b/src/EventListener/InjectPageEntrypointsListener.php new file mode 100644 index 0000000..f8a305b --- /dev/null +++ b/src/EventListener/InjectPageEntrypointsListener.php @@ -0,0 +1,61 @@ +getLayout()?->addEncore) { + return; + } + + $entrypoints = $this->entrypointBuilderFactory->create() + ->setPage($event->getPage()) + ->setLayout($event->getLayout()) + ->build(); + + $this->tagRenderer->reset(); + + foreach ($entrypoints->allActive() as $entrypoint) { + $this->tagRenderer->renderWebpackScriptTags($entrypoint->name, extraAttributes: ['head' => $entrypoint->head]); + if ($entrypoint->requiresCss) { + $this->tagRenderer->renderWebpackLinkTags($entrypoint->name); + } + } + + $this->responseContextAccessor->getResponseContext()->get(HtmlHeadBag::class)->addLinkTag(); + + + + +// $this->pageEntrypoints-> + +// $this->templateAsset->createInstance($event->getPage(), $event->getLayout(), 'encoreEntries'); + +// $context = $this->responseContextAccessor->getResponseContext(); +// $context->get(HtmlHeadBag::class)->addLinkTag() +// $context-> + + + return; + } +} \ No newline at end of file diff --git a/src/Routing/ResponseContext/EntrypointBag.php b/src/Routing/ResponseContext/EntrypointBag.php new file mode 100644 index 0000000..57e03e8 --- /dev/null +++ b/src/Routing/ResponseContext/EntrypointBag.php @@ -0,0 +1,21 @@ +entrypoints; + } + + public function addEntrypoint(string $entrypoint): void + { + $this->entrypoints[] = $entrypoint; + } +} \ No newline at end of file From d03ae477074c692f253b693f6c62fee35e990cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 09:05:03 +0200 Subject: [PATCH 05/20] work on entrypoint creation --- config/services.yml | 2 +- src/EntryPoint/EntryPoint.php | 15 +++++ .../EntryPointBuilderFactory.php} | 11 ++-- src/EntryPoint/EntryPoints.php | 41 ++++++++++++ .../EntryPointsBuilder.php} | 62 ++++++++++++------- src/Entrypoints/Entrypoint.php | 23 ------- src/Entrypoints/Entrypoints.php | 41 ------------ .../InjectPageEntriesListener.php | 47 ++++++++++++++ .../InjectPageEntrypointsListener.php | 61 ------------------ 9 files changed, 149 insertions(+), 154 deletions(-) create mode 100644 src/EntryPoint/EntryPoint.php rename src/{Entrypoints/EntrypointBuilderFactory.php => EntryPoint/EntryPointBuilderFactory.php} (52%) create mode 100644 src/EntryPoint/EntryPoints.php rename src/{Entrypoints/EntrypointsBuilder.php => EntryPoint/EntryPointsBuilder.php} (56%) delete mode 100644 src/Entrypoints/Entrypoint.php delete mode 100644 src/Entrypoints/Entrypoints.php create mode 100644 src/EventListener/InjectPageEntriesListener.php delete mode 100644 src/EventListener/InjectPageEntrypointsListener.php diff --git a/config/services.yml b/config/services.yml index d2ec534..6488ed0 100644 --- a/config/services.yml +++ b/config/services.yml @@ -14,7 +14,7 @@ services: public: true autoconfigure: true - HeimrichHannot\EncoreBundle\Entrypoints\EntrypointBuilderFactory: ~ + HeimrichHannot\EncoreBundle\Asset\EntrypointCollectionFactory: ~ huh.encore.asset.frontend: alias: HeimrichHannot\EncoreBundle\Asset\FrontendAsset diff --git a/src/EntryPoint/EntryPoint.php b/src/EntryPoint/EntryPoint.php new file mode 100644 index 0000000..2521584 --- /dev/null +++ b/src/EntryPoint/EntryPoint.php @@ -0,0 +1,15 @@ +utils, - $this->frontendAsset, $this->entryCollection, ); } diff --git a/src/EntryPoint/EntryPoints.php b/src/EntryPoint/EntryPoints.php new file mode 100644 index 0000000..951d81f --- /dev/null +++ b/src/EntryPoint/EntryPoints.php @@ -0,0 +1,41 @@ +entryPoints[$entryPoint->name] = $entryPoint; + if ($entryPoint->active) { + $this->active[$entryPoint->name] = $entryPoint; + } else { + unset($this->active[$entryPoint->name]); + } + } + + /** + * @return EntryPoint[] + */ + public function all(): array + { + return $this->entryPoints; + } + + /** + * @return EntryPoint[] + */ + public function allActive(): array + { + return $this->active; + } +} \ No newline at end of file diff --git a/src/Entrypoints/EntrypointsBuilder.php b/src/EntryPoint/EntryPointsBuilder.php similarity index 56% rename from src/Entrypoints/EntrypointsBuilder.php rename to src/EntryPoint/EntryPointsBuilder.php index 095989f..bcd8633 100644 --- a/src/Entrypoints/EntrypointsBuilder.php +++ b/src/EntryPoint/EntryPointsBuilder.php @@ -1,6 +1,6 @@ pageModel = $page; $this->pageField = $field; return $this; } - public function setLayout(LayoutModel $layout, string $field = EncoreEntriesSelectField::NAME_DEFAULT): self + public function setLayout(?LayoutModel $layout, string $field = EncoreEntriesSelectField::NAME_DEFAULT): self { $this->layout = $layout; $this->layoutField = $field; return $this; } - public function build(): Entrypoints + public function setFrontendAsset(?FrontendAsset $frontendAsset): self { - $entrypoints = new Entrypoints(); + $this->frontendAsset = $frontendAsset; + return $this; + } + + public function build(): EntryPoints + { + $entryPoints = new EntryPoints(); $available = $this->entryCollection->getEntries(); $available = array_combine(array_column($available, 'name'), $available); $this->available = $available; - foreach ($this->frontendAsset->getActiveEntrypoints() as $entrypoint) { - $this->addEntrypoint( - entrypoints: $entrypoints, - name: $entrypoint, - ); + if ($this->frontendAsset) { + foreach ($this->frontendAsset->getActiveEntrypoints() as $entryPoint) { + $this->addEntryPoint( + entryPoints: $entryPoints, + name: $entryPoint, + origin: FrontendAsset::class, + ); + } } if ($this->pageModel && !$this->layout) { @@ -62,10 +72,12 @@ public function build(): Entrypoints if ($this->layout) { foreach (StringUtil::deserialize($this->layout->{$this->layoutField}, true) as $entrypoint) { - $this->addEntrypoint( - entrypoints: $entrypoints, + $this->addEntryPoint( + entryPoints: $entryPoints, name: $entrypoint['name'] ?? '', - active: (bool)($entrypoint['active'] ?? true) + active: (bool)($entrypoint['active'] ?? true), + origin: 'tl_layout.'.$layout->id, + extension: 'App', ); } } @@ -76,19 +88,20 @@ public function build(): Entrypoints foreach ($pages as $page) { foreach (StringUtil::deserialize($page->{$this->pageField}, true) as $entrypoint) { - $this->addEntrypoint( - entrypoints: $entrypoints, + $this->addEntryPoint( + entryPoints: $entryPoints, name: $entrypoint['name'] ?? '', - active: (bool)($entrypoint['active'] ?? true) + active: (bool)($entrypoint['active'] ?? true), + origin: 'tl_page.'.$page->id, ); } } } - return $entrypoints; + return $entryPoints; } - private function addEntrypoint(Entrypoints $entrypoints, string $name, bool $active = true): void + private function addEntryPoint(EntryPoints $entryPoints, string $name, bool $active = true, string $origin = '', string $extension = ''): void { if ('' === $name) { return; @@ -98,6 +111,13 @@ private function addEntrypoint(Entrypoints $entrypoints, string $name, bool $act return; } - $entrypoints->add(Entrypoint::fromArray($this->available[$name], $active)); + $entryPoints->add(new EntryPoint( + name: $name, + active: $active, + head: $this->available[$name]['head'] ?? false, + requiresCss: (bool)$this->available[$name]['requiresCss'] ?? true, + origin: $origin, + extension: $extension, + )); } } \ No newline at end of file diff --git a/src/Entrypoints/Entrypoint.php b/src/Entrypoints/Entrypoint.php deleted file mode 100644 index a7fb5e7..0000000 --- a/src/Entrypoints/Entrypoint.php +++ /dev/null @@ -1,23 +0,0 @@ -entrypoints[$entrypoint->name] = $entrypoint; - if ($entrypoint->active) { - $this->active[$entrypoint->name] = $entrypoint; - } else { - unset($this->active[$entrypoint->name]); - } - } - - /** - * @return Entrypoint[] - */ - public function all(): array - { - return $this->entrypoints; - } - - /** - * @return Entrypoint[] - */ - public function allActive(): array - { - return $this->active; - } -} \ No newline at end of file diff --git a/src/EventListener/InjectPageEntriesListener.php b/src/EventListener/InjectPageEntriesListener.php new file mode 100644 index 0000000..4fc3e0b --- /dev/null +++ b/src/EventListener/InjectPageEntriesListener.php @@ -0,0 +1,47 @@ +getLayout()?->addEncore) { + return; + } + + $entryPoints = $this->entrypointBuilderFactory->create() + ->setPage($event->getPage()) + ->setLayout($event->getLayout()) + ->setFrontendAsset($this->frontendAsset) + ->build(); + + $this->tagRenderer->reset(); + + foreach ($entryPoints->allActive() as $entrypoint) { + if ($entrypoint->requiresCss) { + $GLOBALS['TL_HEAD'][] = $this->tagRenderer->renderWebpackLinkTags($entrypoint->name); + } + if ($entrypoint->head) { + $GLOBALS['TL_HEAD'][] = $this->tagRenderer->renderWebpackScriptTags($entrypoint->name); + } else { + $GLOBALS['TL_BODY'][] = $this->tagRenderer->renderWebpackScriptTags($entrypoint->name); + } + } + } +} \ No newline at end of file diff --git a/src/EventListener/InjectPageEntrypointsListener.php b/src/EventListener/InjectPageEntrypointsListener.php deleted file mode 100644 index f8a305b..0000000 --- a/src/EventListener/InjectPageEntrypointsListener.php +++ /dev/null @@ -1,61 +0,0 @@ -getLayout()?->addEncore) { - return; - } - - $entrypoints = $this->entrypointBuilderFactory->create() - ->setPage($event->getPage()) - ->setLayout($event->getLayout()) - ->build(); - - $this->tagRenderer->reset(); - - foreach ($entrypoints->allActive() as $entrypoint) { - $this->tagRenderer->renderWebpackScriptTags($entrypoint->name, extraAttributes: ['head' => $entrypoint->head]); - if ($entrypoint->requiresCss) { - $this->tagRenderer->renderWebpackLinkTags($entrypoint->name); - } - } - - $this->responseContextAccessor->getResponseContext()->get(HtmlHeadBag::class)->addLinkTag(); - - - - -// $this->pageEntrypoints-> - -// $this->templateAsset->createInstance($event->getPage(), $event->getLayout(), 'encoreEntries'); - -// $context = $this->responseContextAccessor->getResponseContext(); -// $context->get(HtmlHeadBag::class)->addLinkTag() -// $context-> - - - return; - } -} \ No newline at end of file From c3469b250870622fb9e31bb875bcd2a390db7c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 09:31:59 +0200 Subject: [PATCH 06/20] enhance code, cleanup --- .gitignore | 3 +- config/services.php | 53 +++++++++++++++++++ config/services.yml | 25 --------- src/ContaoManager/Plugin.php | 2 +- src/EntryPoint/EntryPointsBuilder.php | 8 +-- .../InjectPageEntriesListener.php | 6 ++- src/Routing/ResponseContext/EntrypointBag.php | 21 -------- 7 files changed, 64 insertions(+), 54 deletions(-) create mode 100644 config/services.php delete mode 100644 config/services.yml delete mode 100644 src/Routing/ResponseContext/EntrypointBag.php diff --git a/.gitignore b/.gitignore index 4972bf1..02ff242 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ composer.json~ composer.phar .ddev/ .phpunit.result.cache -phpunit.xml.dist.bak \ No newline at end of file +phpunit.xml.dist.bak +.codex \ No newline at end of file diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..c3a3e72 --- /dev/null +++ b/config/services.php @@ -0,0 +1,53 @@ +services(); + + $services + ->defaults() + ->autowire() + ->bind('$bundleConfig', '%huh_encore%') + ->bind('$webDir', '%contao.web_dir%') + ->bind('$encoreCache', service('webpack_encore.cache')) + ->bind(CacheItemPoolInterface::class, service('webpack_encore.cache')) + ->bind(TagRenderer::class, service('webpack_encore.tag_renderer')) + ; + + $services + ->load('HeimrichHannot\\EncoreBundle\\', '../src/{Asset,Collection,Command,DataContainer,EventListener,Helper}/*') + ->exclude('../src/Asset/{EntrypointCollection.php}') + ->public() + ->autoconfigure() + ; + + $services + ->set(EntryPointBuilderFactory::class) + ; + + $services + ->alias('huh.encore.asset.frontend', FrontendAsset::class) + ->public() + ; + + $services + ->alias('huh.encore.asset.template', TemplateAsset::class) + ->public() + ; +}; diff --git a/config/services.yml b/config/services.yml deleted file mode 100644 index 6488ed0..0000000 --- a/config/services.yml +++ /dev/null @@ -1,25 +0,0 @@ -services: - _defaults: - autowire: true - bind: - $bundleConfig: '%huh_encore%' - $webDir: '%contao.web_dir%' - $encoreCache: '@webpack_encore.cache' - Psr\Cache\CacheItemPoolInterface: "@webpack_encore.cache" - Symfony\WebpackEncoreBundle\Asset\TagRenderer: '@webpack_encore.tag_renderer' - - HeimrichHannot\EncoreBundle\: - resource: "../src/{Asset,Collection,Command,DataContainer,EventListener,Helper}/*" - exclude: '../src/Asset/{EntrypointCollection.php}' - public: true - autoconfigure: true - - HeimrichHannot\EncoreBundle\Asset\EntrypointCollectionFactory: ~ - - huh.encore.asset.frontend: - alias: HeimrichHannot\EncoreBundle\Asset\FrontendAsset - public: true - - huh.encore.asset.template: - alias: HeimrichHannot\EncoreBundle\Asset\TemplateAsset - public: true \ No newline at end of file diff --git a/src/ContaoManager/Plugin.php b/src/ContaoManager/Plugin.php index 2b6bf5c..0eda75b 100644 --- a/src/ContaoManager/Plugin.php +++ b/src/ContaoManager/Plugin.php @@ -33,6 +33,6 @@ public function getBundles(ParserInterface $parser): array public function registerContainerConfiguration(LoaderInterface $loader, array $managerConfig): void { $loader->load('@HeimrichHannotEncoreBundle/config/config.yml'); - $loader->load('@HeimrichHannotEncoreBundle/config/services.yml'); + $loader->load('@HeimrichHannotEncoreBundle/config/services.php'); } } diff --git a/src/EntryPoint/EntryPointsBuilder.php b/src/EntryPoint/EntryPointsBuilder.php index bcd8633..5f5645f 100644 --- a/src/EntryPoint/EntryPointsBuilder.php +++ b/src/EntryPoint/EntryPointsBuilder.php @@ -74,9 +74,9 @@ public function build(): EntryPoints foreach (StringUtil::deserialize($this->layout->{$this->layoutField}, true) as $entrypoint) { $this->addEntryPoint( entryPoints: $entryPoints, - name: $entrypoint['name'] ?? '', + name: $entrypoint['entry'] ?? '', active: (bool)($entrypoint['active'] ?? true), - origin: 'tl_layout.'.$layout->id, + origin: 'tl_layout.'.$this->layout->id, extension: 'App', ); } @@ -90,7 +90,7 @@ public function build(): EntryPoints foreach (StringUtil::deserialize($page->{$this->pageField}, true) as $entrypoint) { $this->addEntryPoint( entryPoints: $entryPoints, - name: $entrypoint['name'] ?? '', + name: $entrypoint['entry'] ?? '', active: (bool)($entrypoint['active'] ?? true), origin: 'tl_page.'.$page->id, ); @@ -115,7 +115,7 @@ private function addEntryPoint(EntryPoints $entryPoints, string $name, bool $act name: $name, active: $active, head: $this->available[$name]['head'] ?? false, - requiresCss: (bool)$this->available[$name]['requiresCss'] ?? true, + requiresCss: (bool)($this->available[$name]['requires_css'] ?? true), origin: $origin, extension: $extension, )); diff --git a/src/EventListener/InjectPageEntriesListener.php b/src/EventListener/InjectPageEntriesListener.php index 4fc3e0b..5596d44 100644 --- a/src/EventListener/InjectPageEntriesListener.php +++ b/src/EventListener/InjectPageEntriesListener.php @@ -3,8 +3,8 @@ namespace HeimrichHannot\EncoreBundle\EventListener; use Contao\CoreBundle\Event\LayoutEvent; -use Contao\CoreBundle\Routing\ResponseContext\ResponseContextAccessor; use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; +use HeimrichHannot\EncoreBundle\Asset\GlobalContaoAsset; use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointBuilderFactory; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; use Symfony\WebpackEncoreBundle\Asset\TagRenderer; @@ -12,10 +12,10 @@ class InjectPageEntriesListener { public function __construct( - private readonly ResponseContextAccessor $responseContextAccessor, private readonly TagRenderer $tagRenderer, private readonly EntryPointBuilderFactory $entrypointBuilderFactory, private readonly FrontendAsset $frontendAsset, + private readonly GlobalContaoAsset $globalContaoAsset, ) {} #[AsEventListener] @@ -25,6 +25,8 @@ public function onLayoutEvent(LayoutEvent $event): void return; } + $this->globalContaoAsset->cleanGlobalArrayFromConfiguration(); + $entryPoints = $this->entrypointBuilderFactory->create() ->setPage($event->getPage()) ->setLayout($event->getLayout()) diff --git a/src/Routing/ResponseContext/EntrypointBag.php b/src/Routing/ResponseContext/EntrypointBag.php deleted file mode 100644 index 57e03e8..0000000 --- a/src/Routing/ResponseContext/EntrypointBag.php +++ /dev/null @@ -1,21 +0,0 @@ -entrypoints; - } - - public function addEntrypoint(string $entrypoint): void - { - $this->entrypoints[] = $entrypoint; - } -} \ No newline at end of file From b9b845ff421c0fe5cd8825fdd0a3f0ca22e7d4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 09:32:15 +0200 Subject: [PATCH 07/20] remove dead code --- .../Contao/ReplaceDynamicScriptTagsListener.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php index d62c492..b789fd8 100644 --- a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php +++ b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php @@ -54,19 +54,6 @@ public function __invoke(string $buffer): string return $buffer; } - protected function replaceEncoreTags(string $buffer, PageModel $page, LayoutModel $layout): string - { - $templateAssets = $this->templateAsset->createInstance($page, $layout, 'encoreEntries'); - - $replace = []; - $replace['[[HUH_ENCORE_CSS]]'] = trim($templateAssets->linkTags()); - // caution: always render head first because of global dependencies like jQuery - $replace['[[HUH_ENCORE_HEAD_JS]]'] = trim($templateAssets->headScriptTags()); - $replace['[[HUH_ENCORE_JS]]'] = trim($templateAssets->scriptTags()); - - return str_replace(array_keys($replace), $replace, $buffer); - } - protected function replaceContaoTags(string $buffer, PageModel $page, LayoutModel $layout): string { $templateAssets = $this->templateAsset->createInstance($page, $layout, 'encoreEntries'); From 227d3b224a3410ded951dbe011c550eb21228a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 11:39:45 +0200 Subject: [PATCH 08/20] use builder for legacy layouts, deprecated old implementations, update ConfigurationHelper --- src/Asset/PageEntrypoints.php | 3 + src/Asset/TemplateAsset.php | 3 + src/Asset/TemplateAssetGenerator.php | 3 + src/Event/EncoreEnabledEvent.php | 35 +++++++++++- .../ReplaceDynamicScriptTagsListener.php | 55 ++++++++++--------- .../InjectPageEntriesListener.php | 18 +++++- src/Helper/ConfigurationHelper.php | 50 +++++++++++------ 7 files changed, 120 insertions(+), 47 deletions(-) diff --git a/src/Asset/PageEntrypoints.php b/src/Asset/PageEntrypoints.php index 6d24403..6d7a046 100644 --- a/src/Asset/PageEntrypoints.php +++ b/src/Asset/PageEntrypoints.php @@ -16,6 +16,9 @@ use HeimrichHannot\EncoreBundle\Helper\ArrayHelper; use HeimrichHannot\UtilsBundle\Util\Utils; +/** + * @deprecated Since version 2.2 + */ class PageEntrypoints { protected $jsEntries = []; diff --git a/src/Asset/TemplateAsset.php b/src/Asset/TemplateAsset.php index a194423..52a9e27 100644 --- a/src/Asset/TemplateAsset.php +++ b/src/Asset/TemplateAsset.php @@ -14,6 +14,9 @@ use Twig\Environment; use Twig\Error\RuntimeError; +/** + * @deprecated Since version 2.2 + */ class TemplateAsset { /** diff --git a/src/Asset/TemplateAssetGenerator.php b/src/Asset/TemplateAssetGenerator.php index 2897e72..5edb7c5 100644 --- a/src/Asset/TemplateAssetGenerator.php +++ b/src/Asset/TemplateAssetGenerator.php @@ -14,6 +14,9 @@ use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; +/** + * @deprecated Since 2.2 + */ class TemplateAssetGenerator { /** diff --git a/src/Event/EncoreEnabledEvent.php b/src/Event/EncoreEnabledEvent.php index 0c2e9fc..ff6d5ed 100644 --- a/src/Event/EncoreEnabledEvent.php +++ b/src/Event/EncoreEnabledEvent.php @@ -8,6 +8,7 @@ namespace HeimrichHannot\EncoreBundle\Event; +use Contao\LayoutModel; use Contao\PageModel; use Symfony\Component\HttpFoundation\Request; use Symfony\Contracts\EventDispatcher\Event; @@ -15,14 +16,24 @@ class EncoreEnabledEvent extends Event { public function __construct( - private bool $enabled, - private readonly Request $request, - private readonly ?PageModel $pageModel, + public bool $enabled, + public readonly Request $request, + public readonly ?PageModel $pageModel = null, + public readonly ?LayoutModel $layoutModel = null, ) { } + /** + * @deprecated + */ public function isEnabled(): bool { + trigger_deprecation( + 'heimrichhannot/contao-encore-bundle', + '2.2.0', + 'Use class instead.' + ); + return $this->enabled; } @@ -33,13 +44,31 @@ public function setEnabled(bool $enabled): self return $this; } + /** + * @deprecated + */ public function getRequest(): Request { + trigger_deprecation( + 'heimrichhannot/contao-encore-bundle', + '2.2.0', + 'Use class instead.' + ); + return $this->request; } + /** + * @deprecated + */ public function getPageModel(): ?PageModel { + trigger_deprecation( + 'heimrichhannot/contao-encore-bundle', + '2.2.0', + 'Use class instead.' + ); + return $this->pageModel; } } diff --git a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php index b789fd8..8727647 100644 --- a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php +++ b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php @@ -10,53 +10,58 @@ use Contao\CoreBundle\DependencyInjection\Attribute\AsHook; use Contao\CoreBundle\Framework\ContaoFramework; -use Contao\LayoutModel; -use Contao\PageModel; +use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; use HeimrichHannot\EncoreBundle\Asset\GlobalContaoAsset; -use HeimrichHannot\EncoreBundle\Asset\TemplateAsset; +use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointBuilderFactory; use HeimrichHannot\EncoreBundle\Helper\ConfigurationHelper; use HeimrichHannot\UtilsBundle\Util\Utils; +use Symfony\WebpackEncoreBundle\Asset\TagRenderer; #[AsHook('replaceDynamicScriptTags')] class ReplaceDynamicScriptTagsListener { public function __construct( - protected array $bundleConfig, - private readonly ContaoFramework $contaoFramework, private readonly Utils $utils, - protected TemplateAsset $templateAsset, protected ConfigurationHelper $configurationHelper, private readonly GlobalContaoAsset $globalContaoAsset, + private readonly EntryPointBuilderFactory $entryPointBuilderFactory, + private readonly FrontendAsset $frontendAsset, + private readonly TagRenderer $tagRenderer, ) { } public function __invoke(string $buffer): string { - if (!$this->configurationHelper->isEnabledOnCurrentPage()) { - return $buffer; - } - $pageModel = $this->utils->request()->getCurrentPageModel(); if (!$pageModel) { return $buffer; } - $pageModel->loadDetails(); - - if (!($layout = $this->contaoFramework->getAdapter(LayoutModel::class)->findByPk($pageModel->layoutId ?? $pageModel->layout))) { + if (!$this->configurationHelper->isEnabledOnPage($pageModel)) { return $buffer; } - /* @var LayoutModel|null $layout */ - $buffer = $this->replaceContaoTags($buffer, $pageModel, $layout); - $this->globalContaoAsset->cleanGlobalArrayFromConfiguration(); - return $buffer; - } + $entryPoints = $this->entryPointBuilderFactory->create() + ->setFrontendAsset($this->frontendAsset) + ->setPage($pageModel) + ->build(); - protected function replaceContaoTags(string $buffer, PageModel $page, LayoutModel $layout): string - { - $templateAssets = $this->templateAsset->createInstance($page, $layout, 'encoreEntries'); + $css = ''; + $headJs = ''; + $bodyJs = ''; + foreach ($entryPoints->allActive() as $entrypoint) { + if ($entrypoint->requiresCss) { + $css .= $this->tagRenderer->renderWebpackLinkTags($entrypoint->name); + } + if ($entrypoint->head) { + $headJs .= $this->tagRenderer->renderWebpackScriptTags($entrypoint->name); + } else { + $bodyJs .= $this->tagRenderer->renderWebpackScriptTags($entrypoint->name); + } + } + + $this->globalContaoAsset->cleanGlobalArrayFromConfiguration(); $nonce = ''; if (method_exists(ContaoFramework::class, 'getNonce')) { @@ -64,11 +69,9 @@ protected function replaceContaoTags(string $buffer, PageModel $page, LayoutMode } $replace = []; - $replace["[[TL_CSS$nonce]]"] = "[[TL_CSS$nonce]]" . trim($templateAssets->linkTags()); - - // caution: always render head first because of global dependencies like jQuery - $replace["[[TL_HEAD$nonce]]"] = trim($templateAssets->headScriptTags()) . "[[TL_HEAD$nonce]]"; - $replace["[[TL_BODY$nonce]]"] = trim($templateAssets->scriptTags()) . "[[TL_BODY$nonce]]"; + $replace["[[TL_CSS$nonce]]"] = "[[TL_CSS$nonce]]" . trim($css); + $replace["[[TL_HEAD$nonce]]"] = trim($headJs) . "[[TL_HEAD$nonce]]"; + $replace["[[TL_BODY$nonce]]"] = trim($bodyJs) . "[[TL_BODY$nonce]]"; return str_replace(array_keys($replace), $replace, $buffer); } diff --git a/src/EventListener/InjectPageEntriesListener.php b/src/EventListener/InjectPageEntriesListener.php index 5596d44..18d426f 100644 --- a/src/EventListener/InjectPageEntriesListener.php +++ b/src/EventListener/InjectPageEntriesListener.php @@ -3,10 +3,13 @@ namespace HeimrichHannot\EncoreBundle\EventListener; use Contao\CoreBundle\Event\LayoutEvent; +use Contao\LayoutModel; +use Contao\PageModel; use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; use HeimrichHannot\EncoreBundle\Asset\GlobalContaoAsset; use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointBuilderFactory; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\WebpackEncoreBundle\Asset\TagRenderer; class InjectPageEntriesListener @@ -16,12 +19,13 @@ public function __construct( private readonly EntryPointBuilderFactory $entrypointBuilderFactory, private readonly FrontendAsset $frontendAsset, private readonly GlobalContaoAsset $globalContaoAsset, + private readonly EventDispatcherInterface $eventDispatcher, ) {} #[AsEventListener] public function onLayoutEvent(LayoutEvent $event): void { - if (!$event->getLayout()?->addEncore) { + if (!$this->isEnabled($event->getPage(), $event->getLayout())) { return; } @@ -46,4 +50,16 @@ public function onLayoutEvent(LayoutEvent $event): void } } } + + private function isEnabled(PageModel $page, ?LayoutModel $layout): bool + { + if (!$layout) { + $page->loadDetails(); + $layout = LayoutModel::findByPk($page->layout); + } + + if (!$layout?->addEncore) { + return false; + } + } } \ No newline at end of file diff --git a/src/Helper/ConfigurationHelper.php b/src/Helper/ConfigurationHelper.php index d81f98f..2318030 100644 --- a/src/Helper/ConfigurationHelper.php +++ b/src/Helper/ConfigurationHelper.php @@ -48,22 +48,49 @@ public function __construct( /** * Check if encore is enabled on the current page. + * + * @deprecated + * */ - public function isEnabledOnCurrentPage(?PageModel $pageModel = null): bool + public function isEnabledOnCurrentPage(?PageModel $pageModel = null, ?LayoutModel $layout = null,): bool + { + trigger_deprecation( + 'heimrichhannot/contao-encore-bundle', + '2.2.0', + 'The method "isEnabledOnCurrentPage" is deprecated since version 2.2.0 and will be removed in version 3.0.0. Please use "isEnabledOnPage" instead.' + ); + + return $this->isEnabledOnPage($pageModel ?? $this->getPageModel(), $layout); + } + + public function isEnabledOnPage(PageModel $page, ?LayoutModel $layout = null): bool { $request = $this->requestStack->getCurrentRequest(); - if (!$request) { + if (!$request || !$this->scopeMatcher->isFrontendRequest($request)) { + return false; + } + + if (!$layout) { + $page->loadDetails(); + $layout = LayoutModel::findByPk($page->layoutId ?? $page->layout); + } + + if (!$layout?->addEncore) { return false; } - $result = $this->evaluateIsEnabled($pageModel, $request); + if ('modern' !== $layout->type) { + if (false === $this->evaluateIsEnabled($page, $request)) { + return false; + } + } /** @var EncoreEnabledEvent $event */ $event = $this->eventDispatcher->dispatch( - new EncoreEnabledEvent($result, $request, $pageModel) + new EncoreEnabledEvent(true, $request, $page, $layout) ); - return $event->isEnabled(); + return $event->enabled; } /** @@ -109,10 +136,6 @@ public function getPageModel(): ?PageModel private function evaluateIsEnabled(?PageModel $pageModel, Request $request): bool { - if (!$this->scopeMatcher->isFrontendRequest($request)) { - return false; - } - $parentPageModel = $this->getPageModel(); // Check if error page @@ -130,13 +153,6 @@ private function evaluateIsEnabled(?PageModel $pageModel, Request $request): boo return false; } - $pageModel->loadDetails(); - $layout = $this->contaoFramework->getAdapter(LayoutModel::class)->findByPk($pageModel->layoutId ?? $pageModel->layout); - - if (!$layout || !$layout->addEncore) { - return false; - } - return true; } -} +} \ No newline at end of file From 05d2b097502efaed8d04017290f2bc87b886b2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 11:49:37 +0200 Subject: [PATCH 09/20] update workflow --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51d1b7d..8f55c05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ jobs: tests: name: PHP ${{ matrix.php }} runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} strategy: fail-fast: false matrix: @@ -34,6 +35,7 @@ jobs: coverage: runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -61,6 +63,7 @@ jobs: phpstan: runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -79,6 +82,7 @@ jobs: ecs: name: ECS runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} steps: - name: Setup PHP uses: shivammathur/setup-php@v2 From 3ea1145438e7c8048e572a6b829c1794b4ea73fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 11:54:53 +0200 Subject: [PATCH 10/20] another workflow update --- .github/workflows/ci.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f55c05..279df54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,20 @@ name: CI -on: [ push ] +on: + push: + branches: + - main + - v2 + pull_request: + types: [ opened, reopened, synchronize, ready_for_review ] + branches: + - '**' jobs: tests: name: PHP ${{ matrix.php }} runs-on: ubuntu-latest - if: ${{ !github.event.pull_request.draft }} + if: github.event.pull_request.draft == false strategy: fail-fast: false matrix: @@ -35,7 +43,7 @@ jobs: coverage: runs-on: ubuntu-latest - if: ${{ !github.event.pull_request.draft }} + if: github.event.pull_request.draft == false steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -63,7 +71,7 @@ jobs: phpstan: runs-on: ubuntu-latest - if: ${{ !github.event.pull_request.draft }} + if: github.event.pull_request.draft == false steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -82,7 +90,7 @@ jobs: ecs: name: ECS runs-on: ubuntu-latest - if: ${{ !github.event.pull_request.draft }} + if: github.event.pull_request.draft == false steps: - name: Setup PHP uses: shivammathur/setup-php@v2 From c9d37f01edeeb6c87549f05507e6f144d52d5b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 12:01:38 +0200 Subject: [PATCH 11/20] small fixes --- composer.json | 1 + src/EntryPoint/EntryPointsBuilder.php | 1 + 2 files changed, 2 insertions(+) diff --git a/composer.json b/composer.json index fc205e2..8b1219f 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "symfony/config": "^5.4 || ^6.0 || ^7.0", "symfony/console": "^5.4 || ^6.0 || ^7.0", "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/deprecation-contracts": "^1.0 || ^2.0 || ^3.0", "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", "symfony/http-foundation": "^5.4 || ^6.0 || ^7.0", "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", diff --git a/src/EntryPoint/EntryPointsBuilder.php b/src/EntryPoint/EntryPointsBuilder.php index 5f5645f..8e4324e 100644 --- a/src/EntryPoint/EntryPointsBuilder.php +++ b/src/EntryPoint/EntryPointsBuilder.php @@ -93,6 +93,7 @@ public function build(): EntryPoints name: $entrypoint['entry'] ?? '', active: (bool)($entrypoint['active'] ?? true), origin: 'tl_page.'.$page->id, + extension: 'App', ); } } From 9e0691cee73ed11830f808e93784b9c59e1a8162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 12:14:29 +0200 Subject: [PATCH 12/20] run rector and phpstan --- composer.json | 7 ++--- phpstan.neon | 2 +- rector.php | 26 ++++++++++++++----- src/Asset/PageEntrypoints.php | 4 +-- src/EntryPoint/EntryPoints.php | 2 +- .../ReplaceDynamicScriptTagsListener.php | 6 +---- .../InjectPageEntriesListener.php | 17 +++--------- 7 files changed, 30 insertions(+), 34 deletions(-) diff --git a/composer.json b/composer.json index 8b1219f..ce8804c 100644 --- a/composer.json +++ b/composer.json @@ -37,15 +37,16 @@ "twig/twig": "^1.38.3 || ^2.7 || ^3.0" }, "require-dev": { + "contao/core-bundle": "^4.13", "contao/test-case": "^4.0 || ^5.0", "contao/manager-plugin": "^2.13", "phpunit/phpunit": "^8.0 || ^9.0", "php-coveralls/php-coveralls": "^2.0", "symfony/phpunit-bridge": "^3.2 || ^4.0 || ^5.0 || ^6.0", "heimrichhannot/contao-test-utilities-bundle": "^0.1.4", - "phpstan/phpstan": "^1.12", - "phpstan/phpstan-symfony": "^1.4", - "rector/rector": "^1.2", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-symfony": "^1.4 || ^2.0", + "rector/rector": "^1.2 || ^2.0", "contao/contao-rector": "dev-main", "symplify/easy-coding-standard": "^12.5" }, diff --git a/phpstan.neon b/phpstan.neon index e630b1c..f1071c0 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,7 +2,7 @@ parameters: level: 4 paths: - src - - tests +# - tests - contao universalObjectCratesClasses: - Contao\LayoutModel diff --git a/rector.php b/rector.php index 77d1b97..d31bad3 100644 --- a/rector.php +++ b/rector.php @@ -5,30 +5,42 @@ use Contao\Rector\Set\ContaoLevelSetList; use Contao\Rector\Set\ContaoSetList; use Rector\Config\RectorConfig; +use Rector\Php81\Rector\Array_\ArrayToFirstClassCallableRector; use Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector; use Rector\Set\ValueObject\LevelSetList; use Rector\Symfony\Set\SymfonySetList; use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector; +use Rector\ValueObject\PhpVersion; return RectorConfig::configure() ->withPaths([ __DIR__ . '/src', __DIR__ . '/contao', + __DIR__ . '/config', ]) + ->withPhpVersion(PhpVersion::PHP_84) ->withRules([ AddVoidReturnTypeWhereNoReturnRector::class, - # In Vorbereitung für PHP 8.4: ExplicitNullableParamTypeRector::class ]) - ->withImportNames(importShortClasses: false, removeUnusedImports: true) + ->withImportNames( + importShortClasses: false, + removeUnusedImports: true, + ) + ->withComposerBased( + twig: true, + doctrine: true, + phpunit: true, + symfony: true, + ) ->withSets([ LevelSetList::UP_TO_PHP_81, - SymfonySetList::SYMFONY_54, - SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION, - # Erst mit Symfony 6 (Contao 5) nutzen: - // SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES, ContaoLevelSetList::UP_TO_CONTAO_413, ContaoSetList::FQCN, ContaoSetList::ANNOTATIONS_TO_ATTRIBUTES, - ]); \ No newline at end of file + ]) + ->withSkip([ + ArrayToFirstClassCallableRector::class, + ]) + ; \ No newline at end of file diff --git a/src/Asset/PageEntrypoints.php b/src/Asset/PageEntrypoints.php index 6d7a046..8fecf24 100644 --- a/src/Asset/PageEntrypoints.php +++ b/src/Asset/PageEntrypoints.php @@ -84,9 +84,7 @@ public function collectPageEntries(LayoutModel $layout, PageModel $currentPage, $parents = [$layout]; $parentPages = $this->utils->model()->findParentsRecursively($currentPage, 'pid'); - if (\is_array($parentPages)) { - $parents = array_merge($parents, $parentPages); - } + $parents = array_merge($parents, $parentPages); $parents = array_merge($parents, [$currentPage]); $parents = array_reverse($parents); diff --git a/src/EntryPoint/EntryPoints.php b/src/EntryPoint/EntryPoints.php index 951d81f..a6facf0 100644 --- a/src/EntryPoint/EntryPoints.php +++ b/src/EntryPoint/EntryPoints.php @@ -13,7 +13,7 @@ class EntryPoints */ private array $active = []; - public function add(EntryPoint $entryPoint) + public function add(EntryPoint $entryPoint): void { $this->entryPoints[$entryPoint->name] = $entryPoint; if ($entryPoint->active) { diff --git a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php index 8727647..324dfea 100644 --- a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php +++ b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php @@ -63,11 +63,7 @@ public function __invoke(string $buffer): string $this->globalContaoAsset->cleanGlobalArrayFromConfiguration(); - $nonce = ''; - if (method_exists(ContaoFramework::class, 'getNonce')) { - $nonce = '_' . ContaoFramework::getNonce(); - } - + $nonce = '_' . ContaoFramework::getNonce(); $replace = []; $replace["[[TL_CSS$nonce]]"] = "[[TL_CSS$nonce]]" . trim($css); $replace["[[TL_HEAD$nonce]]"] = trim($headJs) . "[[TL_HEAD$nonce]]"; diff --git a/src/EventListener/InjectPageEntriesListener.php b/src/EventListener/InjectPageEntriesListener.php index 18d426f..47ff812 100644 --- a/src/EventListener/InjectPageEntriesListener.php +++ b/src/EventListener/InjectPageEntriesListener.php @@ -8,6 +8,7 @@ use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; use HeimrichHannot\EncoreBundle\Asset\GlobalContaoAsset; use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointBuilderFactory; +use HeimrichHannot\EncoreBundle\Helper\ConfigurationHelper; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\WebpackEncoreBundle\Asset\TagRenderer; @@ -19,13 +20,13 @@ public function __construct( private readonly EntryPointBuilderFactory $entrypointBuilderFactory, private readonly FrontendAsset $frontendAsset, private readonly GlobalContaoAsset $globalContaoAsset, - private readonly EventDispatcherInterface $eventDispatcher, + private readonly ConfigurationHelper $configurationHelper, ) {} #[AsEventListener] public function onLayoutEvent(LayoutEvent $event): void { - if (!$this->isEnabled($event->getPage(), $event->getLayout())) { + if (!$this->configurationHelper->isEnabledOnPage($event->getPage(), $event->getLayout())) { return; } @@ -50,16 +51,4 @@ public function onLayoutEvent(LayoutEvent $event): void } } } - - private function isEnabled(PageModel $page, ?LayoutModel $layout): bool - { - if (!$layout) { - $page->loadDetails(); - $layout = LayoutModel::findByPk($page->layout); - } - - if (!$layout?->addEncore) { - return false; - } - } } \ No newline at end of file From 300c359a1a399958a2afc6615f643de448e0ab35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 13:30:31 +0200 Subject: [PATCH 13/20] phpstan --- phpstan-baseline.neon | 17 +++++++++++++++-- phpstan.neon | 3 +-- src/EventListener/InjectPageEntriesListener.php | 3 --- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index a0a9f7f..3f32295 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,6 +1,19 @@ parameters: ignoreErrors: - - message: "#^Offset 'fields' on array\\{\\} in isset\\(\\) does not exist\\.$#" + message: '#^Call to method getLayout\(\) on an unknown class Contao\\CoreBundle\\Event\\LayoutEvent\.$#' + identifier: class.notFound count: 2 - path: tests/EventListener/DcaField/EncoreEntriesSelectFieldListenerTest.php + path: src/EventListener/InjectPageEntriesListener.php + + - + message: '#^Call to method getPage\(\) on an unknown class Contao\\CoreBundle\\Event\\LayoutEvent\.$#' + identifier: class.notFound + count: 2 + path: src/EventListener/InjectPageEntriesListener.php + + - + message: '#^Parameter \$event of method HeimrichHannot\\EncoreBundle\\EventListener\\InjectPageEntriesListener\:\:onLayoutEvent\(\) has invalid type Contao\\CoreBundle\\Event\\LayoutEvent\.$#' + identifier: class.notFound + count: 1 + path: src/EventListener/InjectPageEntriesListener.php diff --git a/phpstan.neon b/phpstan.neon index f1071c0..3a4bf3f 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,8 +1,7 @@ parameters: - level: 4 + level: 5 paths: - src -# - tests - contao universalObjectCratesClasses: - Contao\LayoutModel diff --git a/src/EventListener/InjectPageEntriesListener.php b/src/EventListener/InjectPageEntriesListener.php index 47ff812..42c8633 100644 --- a/src/EventListener/InjectPageEntriesListener.php +++ b/src/EventListener/InjectPageEntriesListener.php @@ -3,14 +3,11 @@ namespace HeimrichHannot\EncoreBundle\EventListener; use Contao\CoreBundle\Event\LayoutEvent; -use Contao\LayoutModel; -use Contao\PageModel; use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; use HeimrichHannot\EncoreBundle\Asset\GlobalContaoAsset; use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointBuilderFactory; use HeimrichHannot\EncoreBundle\Helper\ConfigurationHelper; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; -use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\WebpackEncoreBundle\Asset\TagRenderer; class InjectPageEntriesListener From 838c308824581d7249b5bad288658bdf1ed2a329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 13:31:47 +0200 Subject: [PATCH 14/20] ecs --- contao/dca/tl_layout.php | 2 +- src/EntryPoint/EntryPoint.php | 11 ++++++----- src/EntryPoint/EntryPointBuilderFactory.php | 5 +++-- src/EntryPoint/EntryPoints.php | 2 +- src/EntryPoint/EntryPointsBuilder.php | 18 +++++++++++------- .../ReplaceDynamicScriptTagsListener.php | 2 +- .../InjectPageEntriesListener.php | 9 +++++---- src/Helper/ConfigurationHelper.php | 5 ++--- 8 files changed, 30 insertions(+), 24 deletions(-) diff --git a/contao/dca/tl_layout.php b/contao/dca/tl_layout.php index 24eb008..6bb5416 100644 --- a/contao/dca/tl_layout.php +++ b/contao/dca/tl_layout.php @@ -27,7 +27,7 @@ /* * Subpalettes */ -$dca['subpalettes']['addEncore'] = EncoreEntriesSelectField::NAME_DEFAULT.',encoreStylesheetsImportsTemplate,encoreScriptsImportsTemplate'; +$dca['subpalettes']['addEncore'] = EncoreEntriesSelectField::NAME_DEFAULT . ',encoreStylesheetsImportsTemplate,encoreScriptsImportsTemplate'; /** * Fields. diff --git a/src/EntryPoint/EntryPoint.php b/src/EntryPoint/EntryPoint.php index 2521584..e49910b 100644 --- a/src/EntryPoint/EntryPoint.php +++ b/src/EntryPoint/EntryPoint.php @@ -6,10 +6,11 @@ class EntryPoint { public function __construct( public readonly string $name, - public readonly bool $active = true, - public readonly bool $head = false, - public readonly bool $requiresCss = false, + public readonly bool $active = true, + public readonly bool $head = false, + public readonly bool $requiresCss = false, public readonly string $origin = '', public readonly string $extension = '', - ) {} -} \ No newline at end of file + ) { + } +} diff --git a/src/EntryPoint/EntryPointBuilderFactory.php b/src/EntryPoint/EntryPointBuilderFactory.php index 7c2d093..4c5a07f 100644 --- a/src/EntryPoint/EntryPointBuilderFactory.php +++ b/src/EntryPoint/EntryPointBuilderFactory.php @@ -10,7 +10,8 @@ class EntryPointBuilderFactory public function __construct( private readonly Utils $utils, private readonly EntryCollection $entryCollection, - ) {} + ) { + } public function create(): EntryPointsBuilder { @@ -19,4 +20,4 @@ public function create(): EntryPointsBuilder $this->entryCollection, ); } -} \ No newline at end of file +} diff --git a/src/EntryPoint/EntryPoints.php b/src/EntryPoint/EntryPoints.php index a6facf0..f763773 100644 --- a/src/EntryPoint/EntryPoints.php +++ b/src/EntryPoint/EntryPoints.php @@ -38,4 +38,4 @@ public function allActive(): array { return $this->active; } -} \ No newline at end of file +} diff --git a/src/EntryPoint/EntryPointsBuilder.php b/src/EntryPoint/EntryPointsBuilder.php index 8e4324e..738cda7 100644 --- a/src/EntryPoint/EntryPointsBuilder.php +++ b/src/EntryPoint/EntryPointsBuilder.php @@ -23,12 +23,14 @@ class EntryPointsBuilder public function __construct( private readonly Utils $utils, private readonly EntryCollection $entryCollection, - ) {} + ) { + } public function setPage(?PageModel $page, string $field = EncoreEntriesSelectField::NAME_DEFAULT): self { $this->pageModel = $page; $this->pageField = $field; + return $this; } @@ -36,12 +38,14 @@ public function setLayout(?LayoutModel $layout, string $field = EncoreEntriesSel { $this->layout = $layout; $this->layoutField = $field; + return $this; } public function setFrontendAsset(?FrontendAsset $frontendAsset): self { $this->frontendAsset = $frontendAsset; + return $this; } @@ -75,8 +79,8 @@ public function build(): EntryPoints $this->addEntryPoint( entryPoints: $entryPoints, name: $entrypoint['entry'] ?? '', - active: (bool)($entrypoint['active'] ?? true), - origin: 'tl_layout.'.$this->layout->id, + active: (bool) ($entrypoint['active'] ?? true), + origin: 'tl_layout.' . $this->layout->id, extension: 'App', ); } @@ -91,8 +95,8 @@ public function build(): EntryPoints $this->addEntryPoint( entryPoints: $entryPoints, name: $entrypoint['entry'] ?? '', - active: (bool)($entrypoint['active'] ?? true), - origin: 'tl_page.'.$page->id, + active: (bool) ($entrypoint['active'] ?? true), + origin: 'tl_page.' . $page->id, extension: 'App', ); } @@ -116,9 +120,9 @@ private function addEntryPoint(EntryPoints $entryPoints, string $name, bool $act name: $name, active: $active, head: $this->available[$name]['head'] ?? false, - requiresCss: (bool)($this->available[$name]['requires_css'] ?? true), + requiresCss: (bool) ($this->available[$name]['requires_css'] ?? true), origin: $origin, extension: $extension, )); } -} \ No newline at end of file +} diff --git a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php index 324dfea..4f49303 100644 --- a/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php +++ b/src/EventListener/Contao/ReplaceDynamicScriptTagsListener.php @@ -26,7 +26,7 @@ public function __construct( private readonly GlobalContaoAsset $globalContaoAsset, private readonly EntryPointBuilderFactory $entryPointBuilderFactory, private readonly FrontendAsset $frontendAsset, - private readonly TagRenderer $tagRenderer, + private readonly TagRenderer $tagRenderer, ) { } diff --git a/src/EventListener/InjectPageEntriesListener.php b/src/EventListener/InjectPageEntriesListener.php index 42c8633..526db6f 100644 --- a/src/EventListener/InjectPageEntriesListener.php +++ b/src/EventListener/InjectPageEntriesListener.php @@ -13,12 +13,13 @@ class InjectPageEntriesListener { public function __construct( - private readonly TagRenderer $tagRenderer, + private readonly TagRenderer $tagRenderer, private readonly EntryPointBuilderFactory $entrypointBuilderFactory, - private readonly FrontendAsset $frontendAsset, + private readonly FrontendAsset $frontendAsset, private readonly GlobalContaoAsset $globalContaoAsset, private readonly ConfigurationHelper $configurationHelper, - ) {} + ) { + } #[AsEventListener] public function onLayoutEvent(LayoutEvent $event): void @@ -48,4 +49,4 @@ public function onLayoutEvent(LayoutEvent $event): void } } } -} \ No newline at end of file +} diff --git a/src/Helper/ConfigurationHelper.php b/src/Helper/ConfigurationHelper.php index 2318030..88073c2 100644 --- a/src/Helper/ConfigurationHelper.php +++ b/src/Helper/ConfigurationHelper.php @@ -50,9 +50,8 @@ public function __construct( * Check if encore is enabled on the current page. * * @deprecated - * */ - public function isEnabledOnCurrentPage(?PageModel $pageModel = null, ?LayoutModel $layout = null,): bool + public function isEnabledOnCurrentPage(?PageModel $pageModel = null, ?LayoutModel $layout = null): bool { trigger_deprecation( 'heimrichhannot/contao-encore-bundle', @@ -155,4 +154,4 @@ private function evaluateIsEnabled(?PageModel $pageModel, Request $request): boo return true; } -} \ No newline at end of file +} From dd9db02c60d41e00ef92e114e447c6848d63deda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6rner?= Date: Mon, 20 Apr 2026 14:01:21 +0200 Subject: [PATCH 15/20] fix tests, more deprecations --- CHANGELOG.md | 8 + composer.json | 2 +- src/DependencyInjection/Configuration.php | 1 + src/Helper/ConfigurationHelper.php | 12 +- .../ReplaceDynamicScriptTagsListenerTest.php | 185 ++++++++---------- 5 files changed, 106 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 474271e..579cc8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. +## [2.2.0] - 2026-04-20 +- Added: support for modern twig layouts of contao 5.7 +- Added: EntrypointsBuilder concept for retriving current page entrypoints +- Changed: add constant for default field name ([#34](https://github.com/heimrichhannot/contao-encore-bundle/pull/34)) +- Fixed: removed dead or unnecessary code and checks +- Deprecated: `src/Asset/PageEntrypoints.php`, `src/Asset/TemplateAsset.php` and `src/Asset/TemplateAssetGenerator.php` + + ## [2.1.1] - 2026-03-30 - Fixed: compatibility issue with symfony 7 diff --git a/composer.json b/composer.json index ce8804c..3e63f58 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ }, "require-dev": { "contao/core-bundle": "^4.13", - "contao/test-case": "^4.0 || ^5.0", + "contao/test-case": "^4.0", "contao/manager-plugin": "^2.13", "phpunit/phpunit": "^8.0 || ^9.0", "php-coveralls/php-coveralls": "^2.0", diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index ec9ff12..834b2b3 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -20,6 +20,7 @@ public function getConfigTreeBuilder(): TreeBuilder $treeBuilder->getRootNode() ->children() ->arrayNode('templates') + ->setDeprecated('heimrichhannot/contao-encore-bundle', '2.2.0',) ->addDefaultsIfNotSet() ->children() ->arrayNode('imports') diff --git a/src/Helper/ConfigurationHelper.php b/src/Helper/ConfigurationHelper.php index 88073c2..44125a2 100644 --- a/src/Helper/ConfigurationHelper.php +++ b/src/Helper/ConfigurationHelper.php @@ -59,7 +59,13 @@ public function isEnabledOnCurrentPage(?PageModel $pageModel = null, ?LayoutMode 'The method "isEnabledOnCurrentPage" is deprecated since version 2.2.0 and will be removed in version 3.0.0. Please use "isEnabledOnPage" instead.' ); - return $this->isEnabledOnPage($pageModel ?? $this->getPageModel(), $layout); + $pageModel ??= $this->getPageModel(); + + if (null === $pageModel) { + return false; + } + + return $this->isEnabledOnPage($pageModel, $layout); } public function isEnabledOnPage(PageModel $page, ?LayoutModel $layout = null): bool @@ -71,7 +77,9 @@ public function isEnabledOnPage(PageModel $page, ?LayoutModel $layout = null): b if (!$layout) { $page->loadDetails(); - $layout = LayoutModel::findByPk($page->layoutId ?? $page->layout); + $layout = $this->contaoFramework + ->getAdapter(LayoutModel::class) + ->findByPk($page->layoutId ?? $page->layout); } if (!$layout?->addEncore) { diff --git a/tests/EventListener/Contao/ReplaceDynamicScriptTagsListenerTest.php b/tests/EventListener/Contao/ReplaceDynamicScriptTagsListenerTest.php index 9c55c63..0400668 100644 --- a/tests/EventListener/Contao/ReplaceDynamicScriptTagsListenerTest.php +++ b/tests/EventListener/Contao/ReplaceDynamicScriptTagsListenerTest.php @@ -9,161 +9,148 @@ namespace HeimrichHannot\EncoreBundle\Test\EventListener\Contao; use Contao\CoreBundle\Framework\ContaoFramework; -use Contao\CoreBundle\ServiceAnnotation\Page; -use Contao\LayoutModel; use Contao\PageModel; use Contao\TestCase\ContaoTestCase; +use HeimrichHannot\EncoreBundle\Asset\FrontendAsset; use HeimrichHannot\EncoreBundle\Asset\GlobalContaoAsset; -use HeimrichHannot\EncoreBundle\Asset\TemplateAsset; +use HeimrichHannot\EncoreBundle\EntryPoint\EntryPoint; +use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointBuilderFactory; +use HeimrichHannot\EncoreBundle\EntryPoint\EntryPoints; +use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointsBuilder; use HeimrichHannot\EncoreBundle\EventListener\Contao\ReplaceDynamicScriptTagsListener; use HeimrichHannot\EncoreBundle\Helper\ConfigurationHelper; use HeimrichHannot\TestUtilitiesBundle\Mock\ModelMockTrait; use HeimrichHannot\UtilsBundle\Util\RequestUtil; use HeimrichHannot\UtilsBundle\Util\Utils; -use PHPUnit\Framework\MockObject\MockBuilder; -use PHPUnit\Framework\MockObject\MockObject; +use Symfony\WebpackEncoreBundle\Asset\TagRenderer; class ReplaceDynamicScriptTagsListenerTest extends ContaoTestCase { use ModelMockTrait; - /** - * @return ReplaceDynamicScriptTagsListener|MockObject - */ - public function createTestInstance(array $parameter = [], ?MockBuilder $mockBuilder = null) + public function createTestInstance(array $parameter = []): ReplaceDynamicScriptTagsListener { - $parameter['bundleConfig'] = $parameter['bundleConfig'] ?? []; - $parameter['contaoFramework'] = $parameter['contaoFramework'] ?? $this->mockContaoFramework(); $parameter['utils'] = $parameter['utils'] ?? $this->createMock(Utils::class); - $parameter['templateAsset'] = $parameter['templateAsset'] ?? $this->createMock(TemplateAsset::class); $parameter['configurationHelper'] = $parameter['configurationHelper'] ?? $this->createMock(ConfigurationHelper::class); $parameter['globalContaoAsset'] = $parameter['globalContaoAsset'] ?? $this->createMock(GlobalContaoAsset::class); - - if ($mockBuilder) { - $instance = $mockBuilder->setConstructorArgs([ - $parameter['bundleConfig'], - $parameter['contaoFramework'], - $parameter['utils'], - $parameter['templateAsset'], - $parameter['configurationHelper'], - $parameter['globalContaoAsset'], - ])->getMock(); - } else { - $instance = new ReplaceDynamicScriptTagsListener( - $parameter['bundleConfig'], - $parameter['contaoFramework'], - $parameter['utils'], - $parameter['templateAsset'], - $parameter['configurationHelper'], - $parameter['globalContaoAsset'], - ); - } - - return $instance; + $parameter['entryPointBuilderFactory'] = $parameter['entryPointBuilderFactory'] ?? $this->createMock(EntryPointBuilderFactory::class); + $parameter['frontendAsset'] = $parameter['frontendAsset'] ?? $this->createMock(FrontendAsset::class); + $parameter['tagRenderer'] = $parameter['tagRenderer'] ?? $this->createMock(TagRenderer::class); + + return new ReplaceDynamicScriptTagsListener( + $parameter['utils'], + $parameter['configurationHelper'], + $parameter['globalContaoAsset'], + entryPointBuilderFactory: $parameter['entryPointBuilderFactory'], + frontendAsset: $parameter['frontendAsset'], + tagRenderer: $parameter['tagRenderer'], + ); } public function testInvoke() { - // - // Encore not enabled - // - - $configurationHelper = $this->createMock(ConfigurationHelper::class); - $configurationHelper->method('isEnabledOnCurrentPage')->willReturn(false); - - $utils = $this->createMock(Utils::class); - $utils->expects($this->never())->method('request'); - - $instance = $this->createTestInstance([ - 'utils' => $utils, - 'configurationHelper' => $configurationHelper, - ]); - $instance->__invoke('test'); - - // - // No page - // - - $configurationHelper = $this->createMock(ConfigurationHelper::class); - $configurationHelper->method('isEnabledOnCurrentPage')->willReturn(true); - $requestUtil = $this->createMock(RequestUtil::class); $requestUtil->method('getCurrentPageModel')->willReturn(null); + $utils = $this->createMock(Utils::class); $utils->method('request')->willReturn($requestUtil); - $layoutAdapter = $this->mockAdapter(['findByPk']); - $layoutAdapter->expects($this->never())->method('findByPk'); + $configurationHelper = $this->createMock(ConfigurationHelper::class); + $configurationHelper->expects($this->never())->method('isEnabledOnPage'); + + $entryPointBuilderFactory = $this->createMock(EntryPointBuilderFactory::class); + $entryPointBuilderFactory->expects($this->never())->method('create'); - $framework = $this->mockContaoFramework([ - LayoutModel::class => $layoutAdapter, - ]); + $globalContaoAsset = $this->createMock(GlobalContaoAsset::class); + $globalContaoAsset->expects($this->never())->method('cleanGlobalArrayFromConfiguration'); $instance = $this->createTestInstance([ 'utils' => $utils, 'configurationHelper' => $configurationHelper, - 'contaoFramework' => $framework, + 'globalContaoAsset' => $globalContaoAsset, + 'entryPointBuilderFactory' => $entryPointBuilderFactory, ]); - $instance->__invoke('test'); + $this->assertSame('test', $instance->__invoke('test')); - // - // No Layout - // + $pageModel = $this->mockModelObject(PageModel::class, [ + 'id' => 1, + ]); $requestUtil = $this->createMock(RequestUtil::class); - $requestUtil->method('getCurrentPageModel')->willReturn($this->mockModelObject(PageModel::class, [ - 'layoutId' => 3, - ])); + $requestUtil->method('getCurrentPageModel')->willReturn($pageModel); + $utils = $this->createMock(Utils::class); $utils->method('request')->willReturn($requestUtil); - $layoutAdapter = $this->mockAdapter(['findByPk']); - $layoutAdapter->method('findByPk')->willReturn(null); + $configurationHelper = $this->createMock(ConfigurationHelper::class); + $configurationHelper->expects($this->once()) + ->method('isEnabledOnPage') + ->with($pageModel) + ->willReturn(false); - $framework = $this->mockContaoFramework([ - LayoutModel::class => $layoutAdapter, - ]); + $entryPointBuilderFactory = $this->createMock(EntryPointBuilderFactory::class); + $entryPointBuilderFactory->expects($this->never())->method('create'); - $templateAssetMock = $this->createMock(TemplateAsset::class); - $templateAssetMock->method('createInstance')->willReturnSelf(); - $templateAssetMock->method('linkTags')->willReturn(''); - $templateAssetMock->method('scriptTags')->willReturn('