mirror of
https://github.com/symfony/stimulus-bundle.git
synced 2026-04-28 11:43:21 +02:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2236755f4f | |||
| e9b46c5698 | |||
| 985ac22ccb | |||
| 3bb89a8f10 | |||
| a6ecf51bda | |||
| c7983dd3d6 | |||
| 45e90b499c | |||
| 7258efcd1f | |||
| 98b1d60e93 | |||
| fb5a529051 | |||
| bbdd4cbe17 | |||
| 540e76af4f | |||
| 0c019e021c | |||
| 54febb74a2 | |||
| 4348949274 | |||
| 36fae71dad | |||
| c25e53cda7 | |||
| 129a4eb576 | |||
| 4f97b82536 | |||
| de4e102353 | |||
| 2e0faad33f | |||
| f4bec0f6ea | |||
| 3afbe1ed99 | |||
| d7deaf0b77 |
+1
-1
@@ -4,5 +4,5 @@
|
||||
/assets/test export-ignore
|
||||
/assets/vitest.config.mjs export-ignore
|
||||
/doc export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/phpunit.dist.xml export-ignore
|
||||
/tests export-ignore
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@
|
||||
/vendor/
|
||||
/composer.lock
|
||||
/phpunit.xml
|
||||
/.phpunit.result.cache
|
||||
/.phpunit.cache
|
||||
|
||||
/tests/fixtures/var
|
||||
/config/reference.php
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
branches: ['2.x']
|
||||
maintained_branches: ['2.x']
|
||||
branches: ['2.x', '3.x']
|
||||
maintained_branches: ['3.x']
|
||||
doc_dir: 'doc'
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 3.0.0
|
||||
|
||||
- Minimum required Symfony version is now 7.4
|
||||
- Minimum required PHP version is now 8.4
|
||||
- Remove Twig function `ux_controller_link_tags()`, which requires Symfony AssetMapper >=6.4
|
||||
|
||||
## 2.33
|
||||
|
||||
- Change AssetMapper `excluded_patterns` from `**/controllers.json` to `*/controllers.json`
|
||||
|
||||
+13
-10
@@ -13,20 +13,23 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"symfony/config": "^5.4|^6.0|^7.0|^8.0",
|
||||
"symfony/dependency-injection": "^5.4|^6.0|^7.0|^8.0",
|
||||
"symfony/finder": "^5.4|^6.0|^7.0|^8.0",
|
||||
"symfony/http-kernel": "^5.4|^6.0|^7.0|^8.0",
|
||||
"php": ">=8.4",
|
||||
"symfony/config": "^7.4|^8.0",
|
||||
"symfony/dependency-injection": "^7.4|^8.0",
|
||||
"symfony/finder": "^7.4|^8.0",
|
||||
"symfony/http-kernel": "^7.4|^8.0",
|
||||
"twig/twig": "^2.15.3|^3.8",
|
||||
"symfony/deprecation-contracts": "^2.0|^3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/asset-mapper": "<6.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/asset-mapper": "^6.3|^7.0|^8.0",
|
||||
"symfony/framework-bundle": "^5.4|^6.0|^7.0|^8.0",
|
||||
"symfony/phpunit-bridge": "^5.4|^6.0|^7.0|^8.0",
|
||||
"symfony/twig-bundle": "^5.4|^6.0|^7.0|^8.0",
|
||||
"zenstruck/browser": "^1.4"
|
||||
"phpunit/phpunit": "^11.1|^12.0",
|
||||
"symfony/asset-mapper": "^7.4|^8.0",
|
||||
"symfony/framework-bundle": "^7.4|^8.0",
|
||||
"symfony/twig-bundle": "^7.4|^8.0",
|
||||
"zenstruck/browser": "^1.9"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"autoload": {
|
||||
|
||||
@@ -15,8 +15,6 @@ use Symfony\UX\StimulusBundle\AssetMapper\ControllersMapGenerator;
|
||||
use Symfony\UX\StimulusBundle\AssetMapper\StimulusLoaderJavaScriptCompiler;
|
||||
use Symfony\UX\StimulusBundle\Helper\StimulusHelper;
|
||||
use Symfony\UX\StimulusBundle\Twig\StimulusTwigExtension;
|
||||
use Symfony\UX\StimulusBundle\Twig\UxControllersTwigExtension;
|
||||
use Symfony\UX\StimulusBundle\Twig\UxControllersTwigRuntime;
|
||||
use Symfony\UX\StimulusBundle\Ux\UxPackageReader;
|
||||
use Twig\Environment;
|
||||
|
||||
@@ -45,17 +43,6 @@ return static function (ContainerConfigurator $container): void {
|
||||
])
|
||||
|
||||
// symfony/asset-mapper services
|
||||
->set('stimulus.ux_controllers_twig_extension', UxControllersTwigExtension::class)
|
||||
->tag('twig.extension')
|
||||
|
||||
->set('stimulus.ux_controllers_twig_runtime', UxControllersTwigRuntime::class)
|
||||
->args([
|
||||
service('stimulus.asset_mapper.controllers_map_generator'),
|
||||
service('asset_mapper'),
|
||||
service('stimulus.asset_mapper.ux_package_reader'),
|
||||
param('kernel.project_dir'),
|
||||
])
|
||||
->tag('twig.runtime')
|
||||
|
||||
->set('stimulus.asset_mapper.controllers_map_generator', ControllersMapGenerator::class)
|
||||
->args([
|
||||
|
||||
@@ -416,10 +416,6 @@ will import all your custom controllers as well as those from ``controllers.json
|
||||
It will also dynamically enable "debug" mode in Stimulus when your application
|
||||
is running in debug mode.
|
||||
|
||||
.. tip::
|
||||
|
||||
For AssetMapper 6.3 only, you also need a ``{{ ux_controller_link_tags() }}``
|
||||
in ``base.html.twig``. This is not needed in AssetMapper 6.4+.
|
||||
|
||||
With WebpackEncoreBundle
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/bin/.phpunit/phpunit.xsd"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
bootstrap="vendor/autoload.php"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
failOnDeprecation="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1"/>
|
||||
<env name="SHELL_VERBOSITY" value="-1"/>
|
||||
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[self]=0&max[direct]=0"/>
|
||||
<env name="KERNEL_CLASS" value="Symfony\UX\Autocomplete\Tests\Fixtures\Kernel"/>
|
||||
<env name="DATABASE_URL" value="sqlite:///%kernel.project_dir%/var/data.db"/>
|
||||
</php>
|
||||
@@ -22,17 +23,18 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage>
|
||||
<source
|
||||
ignoreSuppressionOfDeprecations="true"
|
||||
ignoreIndirectDeprecations="true"
|
||||
restrictNotices="true"
|
||||
restrictWarnings="true"
|
||||
>
|
||||
<include>
|
||||
<directory>./src</directory>
|
||||
<directory>src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
|
||||
<listeners>
|
||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
|
||||
</listeners>
|
||||
|
||||
<extensions>
|
||||
<extension class="Zenstruck\Browser\Test\BrowserExtension"/>
|
||||
</extensions>
|
||||
<deprecationTrigger>
|
||||
<function>trigger_deprecation</function>
|
||||
</deprecationTrigger>
|
||||
</source>
|
||||
</phpunit>
|
||||
@@ -24,7 +24,6 @@ class RemoveAssetMapperServicesCompiler implements CompilerPassInterface
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('asset_mapper')) {
|
||||
$container->removeDefinition('stimulus.ux_controllers_twig_runtime');
|
||||
$container->removeDefinition('stimulus.asset_mapper.controllers_map_generator');
|
||||
$container->removeDefinition('stimulus.asset_mapper.loader_javascript_compiler');
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\UX\StimulusBundle\Twig;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @author Ryan Weaver <ryan@symfonycasts.com>
|
||||
*/
|
||||
final class UxControllersTwigExtension extends AbstractExtension
|
||||
{
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('ux_controller_link_tags', [UxControllersTwigRuntime::class, 'renderLinkTags'], ['is_safe' => ['html']]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\UX\StimulusBundle\Twig;
|
||||
|
||||
use Symfony\Component\AssetMapper\AssetMapperInterface;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapGenerator;
|
||||
use Symfony\UX\StimulusBundle\AssetMapper\ControllersMapGenerator;
|
||||
use Symfony\UX\StimulusBundle\Ux\UxPackageReader;
|
||||
use Twig\Extension\RuntimeExtensionInterface;
|
||||
|
||||
/**
|
||||
* Returns the link tags for all autoimported CSS files in controllers.json.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @author Ryan Weaver <ryan@symfonycasts.com>
|
||||
*/
|
||||
final class UxControllersTwigRuntime implements RuntimeExtensionInterface
|
||||
{
|
||||
private array $importMap;
|
||||
|
||||
public function __construct(
|
||||
private ControllersMapGenerator $controllersMapGenerator,
|
||||
private AssetMapperInterface $assetMapper,
|
||||
private UxPackageReader $uxPackageReader,
|
||||
private string $projectDir,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CSS <link> tags for all "autoimport" entries in controllers.json.
|
||||
*/
|
||||
public function renderLinkTags(): string
|
||||
{
|
||||
if (class_exists(ImportMapGenerator::class)) {
|
||||
trigger_deprecation('symfony/ux-stimulus-bundle', '2.13.0', 'Calling ux_controller_link_tags() is deprecated and does nothing with symfony/asset-mapper 6.4. The link tags are rendered automatically via the importmap() function.');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
$controllersFile = $this->controllersMapGenerator->getControllersJsonPath();
|
||||
if (!is_file($controllersFile)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents($controllersFile), true, 512, \JSON_THROW_ON_ERROR);
|
||||
$packages = $data['controllers'] ?? [];
|
||||
|
||||
$links = [];
|
||||
foreach ($packages as $uxPackageName => $controllers) {
|
||||
foreach ($controllers as $controllerData) {
|
||||
if (!$controllerData['enabled'] ?? false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($controllerData['autoimport'] ?? [] as $autoImport => $enabled) {
|
||||
if ($enabled) {
|
||||
$links[] = \sprintf('<link rel="stylesheet" href="%s">', $this->getLinkHref($autoImport, $uxPackageName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\n", $links);
|
||||
}
|
||||
|
||||
// duplicated & adapted in ControllersMapGenerator
|
||||
private function getLinkHref(string $autoImport, string $uxPackageName): string
|
||||
{
|
||||
// see if this is a mapped asset path
|
||||
$asset = $this->assetMapper->getAsset($autoImport);
|
||||
if ($asset) {
|
||||
return $asset->publicPath;
|
||||
}
|
||||
|
||||
$slashPosition = strpos($autoImport, '/');
|
||||
if (false === $slashPosition) {
|
||||
throw new \LogicException(\sprintf('The autoimport "%s" is not valid.', $autoImport));
|
||||
}
|
||||
|
||||
// if the first character is @, then the package name is @symfony/ux-cropperjs
|
||||
$parts = explode('/', $autoImport);
|
||||
if (str_starts_with($autoImport, '@')) {
|
||||
$package = implode('/', \array_slice($parts, 0, 2));
|
||||
$file = implode('/', \array_slice($parts, 2));
|
||||
} else {
|
||||
$package = $parts[0];
|
||||
$file = implode('/', \array_slice($parts, 1));
|
||||
}
|
||||
|
||||
if ($package === $uxPackageName) {
|
||||
// this is a file local to the ux package
|
||||
$uxPackageMetadata = $this->uxPackageReader->readPackageMetadata($uxPackageName);
|
||||
$filePath = $uxPackageMetadata->packageDirectory.'/'.$file;
|
||||
if (!is_file($filePath)) {
|
||||
throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This path could not be found in the asset mapper and the file "%s" does not exist in the package path "%s". And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport, $file, $uxPackageMetadata->packageDirectory));
|
||||
}
|
||||
|
||||
$asset = $this->assetMapper->getAssetFromSourcePath($filePath);
|
||||
if (!$asset) {
|
||||
throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This file was found, but the path is not in the asset mapper. And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport));
|
||||
}
|
||||
|
||||
return $asset->publicPath;
|
||||
}
|
||||
|
||||
$importMap = $this->readImportMap();
|
||||
if (!isset($importMap[$package])) {
|
||||
throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This path could not be found in the asset mapper and no "%s" entry was found in importmap.php. And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport, $package));
|
||||
}
|
||||
|
||||
$importMapEntry = $importMap[$package];
|
||||
if (!isset($importMapEntry['url'])) {
|
||||
throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This path could not be found in the asset mapper and no "url" key was found in importmap.php for the package "%s". And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport, $package));
|
||||
}
|
||||
|
||||
$version = $this->parseVersionFromUrl($importMapEntry['url']);
|
||||
|
||||
return $this->getJsDelivrUrl($package, $version, $file);
|
||||
}
|
||||
|
||||
private function readImportMap(): array
|
||||
{
|
||||
if (!isset($this->importMap)) {
|
||||
// this should be dynamic, but for now, we'll hardcode it
|
||||
$path = $this->projectDir.'/importmap.php';
|
||||
$this->importMap = is_file($path) ? (static fn () => include $path)() : [];
|
||||
}
|
||||
|
||||
return $this->importMap;
|
||||
}
|
||||
|
||||
private function parseVersionFromUrl(string $url): ?string
|
||||
{
|
||||
$versionPattern = '/(?<=@)\d+(?:\.\d+)+/';
|
||||
if (!preg_match($versionPattern, $url, $matches)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
private function getJsDelivrUrl(string $package, ?string $version, string $file): string
|
||||
{
|
||||
$version ??= 'latest';
|
||||
$package = str_replace('@', '', $package);
|
||||
|
||||
return \sprintf('https://cdn.jsdelivr.net/npm/%s@%s/%s', $package, $version, $file);
|
||||
}
|
||||
|
||||
private function shortControllersPath(): string
|
||||
{
|
||||
$path = $this->controllersMapGenerator->getControllersJsonPath();
|
||||
$path = realpath($path);
|
||||
$projectDir = realpath($this->projectDir);
|
||||
if (!str_starts_with($path, $projectDir)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return str_replace($projectDir, '', $path);
|
||||
}
|
||||
}
|
||||
@@ -22,13 +22,6 @@ use Symfony\UX\StimulusBundle\Ux\UxPackageMetadata;
|
||||
|
||||
class AutoImportLocatorTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
if (!class_exists(ImportMapConfigReader::class)) {
|
||||
$this->markTestSkipped('Test requires AssetMapper >= 6.4.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testLocateAutoImportCanHandleAssetMapperPath()
|
||||
{
|
||||
$assetMapper = $this->createMock(AssetMapperInterface::class);
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace Symfony\UX\StimulusBundle\Tests\AssetMapper;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\AssetMapper\AssetMapperInterface;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader;
|
||||
use Symfony\Component\AssetMapper\MappedAsset;
|
||||
use Symfony\UX\StimulusBundle\AssetMapper\AutoImportLocator;
|
||||
use Symfony\UX\StimulusBundle\AssetMapper\ControllersMapGenerator;
|
||||
@@ -54,17 +53,11 @@ class ControllersMapGeneratorTest extends TestCase
|
||||
$packageReader = new UxPackageReader(__DIR__.'/../fixtures');
|
||||
|
||||
$autoImportLocator = $this->createMock(AutoImportLocator::class);
|
||||
if (class_exists(ImportMapConfigReader::class)) {
|
||||
$autoImportLocator->expects($this->any())
|
||||
->method('locateAutoImport')
|
||||
->willReturnCallback(static function ($path) {
|
||||
return new MappedControllerAutoImport('/path/to'.$path, false);
|
||||
});
|
||||
} else {
|
||||
// @legacy for AssetMapper 6.3
|
||||
$autoImportLocator->expects($this->never())
|
||||
->method('locateAutoImport');
|
||||
}
|
||||
$autoImportLocator->expects($this->any())
|
||||
->method('locateAutoImport')
|
||||
->willReturnCallback(static function ($path) {
|
||||
return new MappedControllerAutoImport('/path/to'.$path, false);
|
||||
});
|
||||
|
||||
$generator = new ControllersMapGenerator(
|
||||
$mapper,
|
||||
@@ -106,11 +99,7 @@ class ControllersMapGeneratorTest extends TestCase
|
||||
$this->assertSame('fake-vendor/ux-package1/package-controller-second.js', $controllerSecond->asset->logicalPath);
|
||||
// lazy from user's controller.json
|
||||
$this->assertTrue($controllerSecond->isLazy);
|
||||
// @legacy: assert can be without the conditional for AssetMapper 6.4+
|
||||
if (class_exists(ImportMapConfigReader::class)) {
|
||||
// 4 auto imports from package.json
|
||||
$this->assertCount(4, $controllerSecond->autoImports);
|
||||
}
|
||||
$this->assertCount(4, $controllerSecond->autoImports);
|
||||
|
||||
$helloControllerFromPackage = $map['fake-vendor--ux-package2--hello-controller'];
|
||||
$this->assertSame('fake-vendor/ux-package2/package-hello-controller.js', $helloControllerFromPackage->asset->logicalPath);
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace Symfony\UX\StimulusBundle\Tests\AssetMapper;
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\UX\StimulusBundle\Tests\fixtures\StimulusTestKernel;
|
||||
use Zenstruck\Browser\Test\HasBrowser;
|
||||
@@ -33,123 +32,79 @@ class StimulusControllerLoaderFunctionalTest extends WebTestCase
|
||||
|
||||
$crawler = $this->browser()
|
||||
->get('/')
|
||||
->crawler()
|
||||
;
|
||||
->crawler();
|
||||
|
||||
$importMapJson = $crawler->filter('script[type="importmap"]')->html();
|
||||
$importMap = json_decode($importMapJson, true);
|
||||
$importMapKeys = array_keys($importMap['imports']);
|
||||
|
||||
if (class_exists(ImportMapConfigReader::class)) {
|
||||
// filter out items ending in .css
|
||||
$importMapJsKeys = array_filter($importMapKeys, static function ($key) {
|
||||
return '.css' !== substr($key, -4);
|
||||
});
|
||||
$importMapCssKeys = array_filter($importMapKeys, static function ($key) {
|
||||
return '.css' === substr($key, -4);
|
||||
});
|
||||
sort($importMapJsKeys);
|
||||
$this->assertSame([
|
||||
// 1x import from loader.js (which is aliased to @symfony/stimulus-bundle via importmap)
|
||||
'/assets/@symfony/stimulus-bundle/controllers.js',
|
||||
// 7x from "controllers" (hello is overridden)
|
||||
'/assets/controllers/bye_controller.js',
|
||||
'/assets/controllers/hello-with-dashes-controller.js',
|
||||
'/assets/controllers/hello_with_underscores-controller.js',
|
||||
'/assets/controllers/subdir/deeper-controller.js',
|
||||
'/assets/controllers/subdir/deeper-with-dashes-controller.js',
|
||||
'/assets/controllers/subdir/deeper_with_underscores-controller.js',
|
||||
'/assets/controllers/typescript-controller.ts',
|
||||
// 2x from UX packages, which are enabled in controllers.json
|
||||
'/assets/fake-vendor/ux-package1/package-controller-second.js',
|
||||
'/assets/fake-vendor/ux-package2/package-hello-controller.js',
|
||||
// 4x from more-controllers
|
||||
'/assets/more-controllers/excluded-controller.js',
|
||||
'/assets/more-controllers/hello-controller.js',
|
||||
'/assets/more-controllers/minified-controller.js',
|
||||
'/assets/more-controllers/other-controller.js',
|
||||
// 5x from importmap.php
|
||||
'@hotwired/stimulus',
|
||||
'@scoped/needed-vendor',
|
||||
'@symfony/stimulus-bundle',
|
||||
'app',
|
||||
'needed-vendor',
|
||||
], array_values($importMapJsKeys));
|
||||
// filter out items ending in .css
|
||||
$importMapJsKeys = array_filter($importMapKeys, static function ($key) {
|
||||
return '.css' !== substr($key, -4);
|
||||
});
|
||||
$importMapCssKeys = array_filter($importMapKeys, static function ($key) {
|
||||
return '.css' === substr($key, -4);
|
||||
});
|
||||
sort($importMapJsKeys);
|
||||
$this->assertSame([
|
||||
// 1x import from loader.js (which is aliased to @symfony/stimulus-bundle via importmap)
|
||||
'/assets/@symfony/stimulus-bundle/controllers.js',
|
||||
// 7x from "controllers" (hello is overridden)
|
||||
'/assets/controllers/bye_controller.js',
|
||||
'/assets/controllers/hello-with-dashes-controller.js',
|
||||
'/assets/controllers/hello_with_underscores-controller.js',
|
||||
'/assets/controllers/subdir/deeper-controller.js',
|
||||
'/assets/controllers/subdir/deeper-with-dashes-controller.js',
|
||||
'/assets/controllers/subdir/deeper_with_underscores-controller.js',
|
||||
'/assets/controllers/typescript-controller.ts',
|
||||
// 2x from UX packages, which are enabled in controllers.json
|
||||
'/assets/fake-vendor/ux-package1/package-controller-second.js',
|
||||
'/assets/fake-vendor/ux-package2/package-hello-controller.js',
|
||||
// 4x from more-controllers
|
||||
'/assets/more-controllers/excluded-controller.js',
|
||||
'/assets/more-controllers/hello-controller.js',
|
||||
'/assets/more-controllers/minified-controller.js',
|
||||
'/assets/more-controllers/other-controller.js',
|
||||
// 5x from importmap.php
|
||||
'@hotwired/stimulus',
|
||||
'@scoped/needed-vendor',
|
||||
'@symfony/stimulus-bundle',
|
||||
'app',
|
||||
'needed-vendor',
|
||||
], array_values($importMapJsKeys));
|
||||
|
||||
// the autoimport CSS
|
||||
$this->assertSame([
|
||||
'/assets/in/asset/mapper/controller_second1.css',
|
||||
// enabled => false
|
||||
// '/assets/in/asset/mapper/controller_second2.css',
|
||||
'/assets/fake-vendor/ux-package1/styles.css',
|
||||
// the autoimport CSS
|
||||
$this->assertSame([
|
||||
'/assets/in/asset/mapper/controller_second1.css',
|
||||
// enabled => false
|
||||
// '/assets/in/asset/mapper/controller_second2.css',
|
||||
'/assets/fake-vendor/ux-package1/styles.css',
|
||||
|
||||
// 2x from importmap.php: so they should, of course, be here.
|
||||
// But our compiler should not add "path-based" entries
|
||||
// '/assets/vendor/needed-vendor/file.css',
|
||||
// '/assets/vendor/@scoped/needed-vendor/the/file2.css',
|
||||
'needed-vendor/file.css',
|
||||
'@scoped/needed-vendor/the/file2.css',
|
||||
], array_values($importMapCssKeys));
|
||||
// 2x from importmap.php: so they should, of course, be here.
|
||||
// But our compiler should not add "path-based" entries
|
||||
// '/assets/vendor/needed-vendor/file.css',
|
||||
// '/assets/vendor/@scoped/needed-vendor/the/file2.css',
|
||||
'needed-vendor/file.css',
|
||||
'@scoped/needed-vendor/the/file2.css',
|
||||
], array_values($importMapCssKeys));
|
||||
|
||||
// "app" is the entry. So, all non-lazy controllers should be preloaded:
|
||||
$preLoadHrefs = $crawler->filter('link[rel="modulepreload"]')->each(static function ($link) {
|
||||
return $link->attr('href');
|
||||
});
|
||||
$this->assertCount(12, $preLoadHrefs);
|
||||
sort($preLoadHrefs);
|
||||
$this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/controllers-', $preLoadHrefs[0]);
|
||||
$this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/loader-', $preLoadHrefs[1]);
|
||||
$this->assertStringStartsWith('/assets/controllers/hello-with-dashes-controller-', $preLoadHrefs[3]);
|
||||
$this->assertStringStartsWith('/assets/controllers/hello_with_underscores-controller-', $preLoadHrefs[4]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper-controller-', $preLoadHrefs[5]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper-with-dashes-controller-', $preLoadHrefs[6]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper_with_underscores-controller-', $preLoadHrefs[7]);
|
||||
$this->assertStringStartsWith('/assets/controllers/typescript-controller-', $preLoadHrefs[8]);
|
||||
$this->assertStringStartsWith('/assets/fake-vendor/ux-package2/package-hello-controller-', $preLoadHrefs[9]);
|
||||
$this->assertStringStartsWith('/assets/more-controllers/hello-controller-', $preLoadHrefs[10]);
|
||||
$this->assertStringStartsWith('/assets/vendor/@hotwired/stimulus/stimulus.index', $preLoadHrefs[11]);
|
||||
} else {
|
||||
// legacy
|
||||
$this->assertSame([
|
||||
// 1x import from loader.js (which is aliased to @symfony/stimulus-bundle via importmap)
|
||||
'/assets/@symfony/stimulus-bundle/controllers.js',
|
||||
// 6x from "controllers" (hello is overridden)
|
||||
'/assets/controllers/bye_controller.js',
|
||||
'/assets/controllers/hello-with-dashes-controller.js',
|
||||
'/assets/controllers/hello_with_underscores-controller.js',
|
||||
'/assets/controllers/subdir/deeper-controller.js',
|
||||
'/assets/controllers/subdir/deeper-with-dashes-controller.js',
|
||||
'/assets/controllers/subdir/deeper_with_underscores-controller.js',
|
||||
// 2x from UX packages, which are enabled in controllers.json
|
||||
'/assets/fake-vendor/ux-package1/package-controller-second.js',
|
||||
'/assets/fake-vendor/ux-package2/package-hello-controller.js',
|
||||
// 2x from more-controllers
|
||||
'/assets/more-controllers/hello-controller.js',
|
||||
'/assets/more-controllers/other-controller.js',
|
||||
// 5x from importmap.php
|
||||
'@hotwired/stimulus',
|
||||
'@scoped/needed-vendor',
|
||||
'@symfony/stimulus-bundle',
|
||||
'app',
|
||||
'needed-vendor',
|
||||
], $importMapKeys);
|
||||
|
||||
// "app" & loader.js are pre-loaded. So, all non-lazy controllers should be preloaded:
|
||||
$preLoadHrefs = $crawler->filter('link[rel="modulepreload"]')->each(static function ($link) {
|
||||
return $link->attr('href');
|
||||
});
|
||||
$this->assertCount(10, $preLoadHrefs);
|
||||
sort($preLoadHrefs);
|
||||
$this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/controllers-', $preLoadHrefs[0]);
|
||||
$this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/loader-', $preLoadHrefs[1]);
|
||||
$this->assertStringStartsWith('/assets/controllers/hello-with-dashes-controller-', $preLoadHrefs[2]);
|
||||
$this->assertStringStartsWith('/assets/controllers/hello_with_underscores-controller-', $preLoadHrefs[3]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper-controller-', $preLoadHrefs[4]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper-with-dashes-controller-', $preLoadHrefs[5]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper_with_underscores-controller-', $preLoadHrefs[6]);
|
||||
$this->assertStringStartsWith('/assets/fake-vendor/ux-package2/package-hello-controller-', $preLoadHrefs[7]);
|
||||
$this->assertStringStartsWith('/assets/more-controllers/hello-controller-', $preLoadHrefs[8]);
|
||||
}
|
||||
// "app" is the entry. So, all non-lazy controllers should be preloaded:
|
||||
$preLoadHrefs = $crawler->filter('link[rel="modulepreload"]')->each(static function ($link) {
|
||||
return $link->attr('href');
|
||||
});
|
||||
$this->assertCount(12, $preLoadHrefs);
|
||||
sort($preLoadHrefs);
|
||||
$this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/controllers-', $preLoadHrefs[0]);
|
||||
$this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/loader-', $preLoadHrefs[1]);
|
||||
$this->assertStringStartsWith('/assets/controllers/hello-with-dashes-controller-', $preLoadHrefs[3]);
|
||||
$this->assertStringStartsWith('/assets/controllers/hello_with_underscores-controller-', $preLoadHrefs[4]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper-controller-', $preLoadHrefs[5]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper-with-dashes-controller-', $preLoadHrefs[6]);
|
||||
$this->assertStringStartsWith('/assets/controllers/subdir/deeper_with_underscores-controller-', $preLoadHrefs[7]);
|
||||
$this->assertStringStartsWith('/assets/controllers/typescript-controller-', $preLoadHrefs[8]);
|
||||
$this->assertStringStartsWith('/assets/fake-vendor/ux-package2/package-hello-controller-', $preLoadHrefs[9]);
|
||||
$this->assertStringStartsWith('/assets/more-controllers/hello-controller-', $preLoadHrefs[10]);
|
||||
$this->assertStringStartsWith('/assets/vendor/@hotwired/stimulus/stimulus.index', $preLoadHrefs[11]);
|
||||
}
|
||||
|
||||
protected static function getKernelClass(): string
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\UX\StimulusBundle\Tests\Dto;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\UX\StimulusBundle\Dto\StimulusAttributes;
|
||||
use Twig\Environment;
|
||||
@@ -149,9 +150,7 @@ final class StimulusAttributesTest extends TestCase
|
||||
$this->assertSame(['foo' => 'bar baz'], $this->stimulusAttributes->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideAddComplexActionData
|
||||
*/
|
||||
#[DataProvider('provideAddComplexActionData')]
|
||||
public function testAddComplexAction(string $controllerName, string $actionName, ?string $eventName, string $expectedAction)
|
||||
{
|
||||
$this->stimulusAttributes->addAction($controllerName, $actionName, $eventName);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\UX\StimulusBundle\Tests\Twig;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\UX\StimulusBundle\Helper\StimulusHelper;
|
||||
use Symfony\UX\StimulusBundle\Tests\StimulusIntegrationTestKernel;
|
||||
@@ -29,9 +30,7 @@ final class StimulusTwigExtensionTest extends TestCase
|
||||
$this->twig = $container->get(Environment::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideRenderStimulusController
|
||||
*/
|
||||
#[DataProvider('provideRenderStimulusController')]
|
||||
public function testRenderStimulusController(string $controllerName, array $controllerValues, array $controllerClasses, array $controllerOutlets, string $expectedString, array $expectedArray)
|
||||
{
|
||||
$extension = new StimulusTwigExtension(new StimulusHelper($this->twig));
|
||||
@@ -140,9 +139,7 @@ final class StimulusTwigExtensionTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideRenderStimulusAction
|
||||
*/
|
||||
#[DataProvider('provideRenderStimulusAction')]
|
||||
public function testRenderStimulusAction(string $controllerName, ?string $actionName, ?string $eventName, array $parameters, string $expectedString, array $expectedArray)
|
||||
{
|
||||
$extension = new StimulusTwigExtension(new StimulusHelper($this->twig));
|
||||
@@ -218,9 +215,7 @@ final class StimulusTwigExtensionTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideRenderStimulusTarget
|
||||
*/
|
||||
#[DataProvider('provideRenderStimulusTarget')]
|
||||
public function testRenderStimulusTarget(string $controllerName, ?string $targetName, string $expectedString, array $expectedArray)
|
||||
{
|
||||
$extension = new StimulusTwigExtension(new StimulusHelper($this->twig));
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\UX\StimulusBundle\Tests\Twig;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\AssetMapper\AssetMapperInterface;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader;
|
||||
use Symfony\Component\AssetMapper\MappedAsset;
|
||||
use Symfony\UX\StimulusBundle\AssetMapper\ControllersMapGenerator;
|
||||
use Symfony\UX\StimulusBundle\Twig\UxControllersTwigRuntime;
|
||||
use Symfony\UX\StimulusBundle\Ux\UxPackageReader;
|
||||
|
||||
class UxControllersTwigRuntimeTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testRenderLinkTags()
|
||||
{
|
||||
if (class_exists(ImportMapConfigReader::class)) {
|
||||
$this->markTestSkipped('Skip test for AssetMapper 6.4+');
|
||||
}
|
||||
|
||||
$controllersMapGenerator = $this->createMock(ControllersMapGenerator::class);
|
||||
$controllersMapGenerator->expects($this->any())
|
||||
->method('getControllersJsonPath')
|
||||
->willReturn(__DIR__.'/../fixtures/assets/controllers.json')
|
||||
;
|
||||
|
||||
$assetMapper = $this->createMock(AssetMapperInterface::class);
|
||||
$assetMapper->expects($this->any())
|
||||
->method('getAsset')
|
||||
->willReturnCallback(static function ($path) {
|
||||
if (str_starts_with($path, 'in/asset/mapper')) {
|
||||
return new MappedAsset(basename($path), publicPath: '/assets/mapper/'.basename($path));
|
||||
}
|
||||
|
||||
if (str_starts_with($path, '@fake-vendor/ux-package1')) {
|
||||
return new MappedAsset('fake-vendor/ux-package1/'.basename($path), publicPath: '/assets/@fake-vendor/ux-package1/'.basename($path));
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
$runtime = new UxControllersTwigRuntime(
|
||||
$controllersMapGenerator,
|
||||
$assetMapper,
|
||||
new UxPackageReader(__DIR__.'/../fixtures'),
|
||||
__DIR__.'/../fixtures/legacy'
|
||||
);
|
||||
|
||||
$this->assertStringNotContainsString(
|
||||
'controller_first.css',
|
||||
$runtime->renderLinkTags()
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'href="/assets/mapper/controller_second1.css"',
|
||||
$runtime->renderLinkTags()
|
||||
);
|
||||
$this->assertStringNotContainsString(
|
||||
'controller_second2.css',
|
||||
$runtime->renderLinkTags()
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'href="/assets/@fake-vendor/ux-package1/styles.css"',
|
||||
$runtime->renderLinkTags()
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'href="https://cdn.jsdelivr.net/npm/needed-vendor@3.2.0/file.css"',
|
||||
$runtime->renderLinkTags()
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'href="https://cdn.jsdelivr.net/npm/scoped/needed-vendor@1.2.3/the/file2.css"',
|
||||
$runtime->renderLinkTags()
|
||||
);
|
||||
|
||||
// loop through a controllers.json file with several autoimports
|
||||
// cases for the assets:
|
||||
// 1) asset path is in the pipeline
|
||||
// 2) path starts with the "package name" (try with scoped and non-scoped)
|
||||
// then look right inside the package
|
||||
// 3) look inside importmap.php for a "url" package and map to jsdelivr
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\ErrorHandler\ErrorHandler;
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
// @see https://github.com/symfony/symfony/issues/53812
|
||||
ErrorHandler::register(null, false);
|
||||
+1
-2
@@ -15,7 +15,6 @@ use Psr\Log\NullLogger;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Bundle\TwigBundle\TwigBundle;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -60,7 +59,7 @@ class StimulusTestKernel extends Kernel
|
||||
__DIR__.'/vendor/fake-vendor/ux-package2/Resources/assets/dist' => 'fake-vendor/ux-package2',
|
||||
],
|
||||
// @legacy
|
||||
'importmap_path' => '%kernel.project_dir%/'.(class_exists(ImportMapConfigReader::class) ? 'importmap.php' : 'legacy/importmap.php'),
|
||||
'importmap_path' => '%kernel.project_dir%/importmap.php',
|
||||
],
|
||||
'test' => true,
|
||||
...(self::VERSION_ID >= 60200 ? [
|
||||
|
||||
Vendored
-30
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// @legacy for AssetMapper 6.3 support
|
||||
return [
|
||||
'app' => [
|
||||
'path' => 'app.js',
|
||||
'entrypoint' => true,
|
||||
],
|
||||
'@hotwired/stimulus' => [
|
||||
'url' => 'https://ga.jspm.io/npm:@hotwired/stimulus@3.2.1/dist/stimulus.js',
|
||||
],
|
||||
'@symfony/stimulus-bundle' => [
|
||||
'path' => '@symfony/stimulus-bundle/loader.js',
|
||||
],
|
||||
'needed-vendor' => [
|
||||
'url' => 'https://cdn.jsdelivr.net/npm/needed-vendor@3.2.0/dist/needed-vendor+esm',
|
||||
],
|
||||
'@scoped/needed-vendor' => [
|
||||
'url' => 'https://cdn.jsdelivr.net/npm/@scoped/needed-vendor@1.2.3',
|
||||
],
|
||||
];
|
||||
Reference in New Issue
Block a user