8000 [AssetMapper] Allowing for files to be written to some non-local loca… · symfony/symfony@11050dc · GitHub
[go: up one dir, main page]

Skip to content

Commit 11050dc

Browse files
committed
[AssetMapper] Allowing for files to be written to some non-local location
1 parent b6418aa commit 11050dc

20 files changed

+349
-163
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,13 +1353,17 @@ private function registerAssetMapperConfiguration(array $config, ContainerBuilde
13531353
->setArgument(0, $paths)
13541354
->setArgument(2, $excludedPathPatterns);
13551355

1356-
$publicDirName = $this->getPublicDirectoryName($container);
13571356
$container->getDefinition('asset_mapper.public_assets_path_resolver')
1358-
->setArgument(1, $config['public_prefix'])
1359-
->setArgument(2, $publicDirName);
1357+
->setArgument(0, $config['public_prefix']);
13601358

1361-
$container->getDefinition('asset_mapper.command.compile')
1362-
->setArgument(5, $publicDirName);
1359+
$publicDirectory = $this->getPublicDirectory($container);
1360+
$publicAssetsDirectory = rtrim($publicDirectory.'/'.ltrim($config['public_prefix'], '/'), '/');
1361+
$container->getDefinition('asset_mapper.local_public_assets_filesystem')
1362+
->setArgument(0, $publicDirectory)
1363+
;
1364+
1365+
$container->getDefinition('asset_mapper.compiled_asset_mapper_config_reader')
1366+
->setArgument(0, $publicAssetsDirectory);
13631367

13641368
if (!$config['server']) {
13651369
$container->removeDefinition('asset_mapper.dev_server_subscriber');
@@ -3163,11 +3167,12 @@ private function writeConfigEnabled(string $path, bool $value, array &$config):
31633167
$config['enabled'] = $value;
31643168
}
31653169

3166-
private function getPublicDirectoryName(ContainerBuilder $container): string
3170+
private function getPublicDirectory(ContainerBuilder $container): string
31673171
{
3168-
$defaultPublicDir = 'public';
3172+
$projectDir = $container->getParameter('kernel.project_dir');
3173+
$defaultPublicDir = $projectDir.'/public';
31693174

3170-
$composerFilePath = $container->getParameter('kernel.project_dir').'/composer.json';
3175+
$composerFilePath = $projectDir.'/composer.json';
31713176

31723177
if (!file_exists($composerFilePath)) {
31733178
return $defaultPublicDir;
@@ -3176,6 +3181,6 @@ private function getPublicDirectoryName(ContainerBuilder $container): string
31763181
$container->addResource(new FileResource($composerFilePath));
31773182
$composerConfig = json_decode(file_get_contents($composerFilePath), true);
31783183

3179-
return $composerConfig['extra']['public-dir'] ?? $defaultPublicDir;
3184+
return isset($composerConfig['extra']['public-dir']) ? $projectDir.'/'.$composerConfig['extra']['public-dir'] : $defaultPublicDir;
31803185
}
31813186
}

src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Symfony\Component\AssetMapper\Command\ImportMapRemoveCommand;
2525
use Symfony\Component\AssetMapper\Command\ImportMapRequireCommand;
2626
use Symfony\Component\AssetMapper\Command\ImportMapUpdateCommand;
27+
use Symfony\Component\AssetMapper\CompiledAssetMapperConfigReader;
2728
use Symfony\Component\AssetMapper\Compiler\CssAssetUrlCompiler;
2829
use Symfony\Component\AssetMapper\Compiler\JavaScriptImportPathCompiler;
2930
use Symfony\Component\AssetMapper\Compiler\SourceMappingUrlsCompiler;
@@ -40,6 +41,7 @@
4041
use Symfony\Component\AssetMapper\ImportMap\RemotePackageStorage;
4142
use Symfony\Component\AssetMapper\ImportMap\Resolver\JsDelivrEsmResolver;
4243
use Symfony\Component\AssetMapper\MapperAwareAssetPackage;
44+
use Symfony\Component\AssetMapper\Path\LocalPublicAssetsFilesystem;
4345
use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolver;
4446

4547
return static function (ContainerConfigurator $container) {
@@ -48,7 +50,7 @@
4850
->args([
4951
service('asset_mapper.repository'),
5052
service('asset_mapper.mapped_asset_factory'),
51-
service('asset_mapper.public_assets_path_resolver'),
53+
service('asset_mapper.compiled_asset_mapper_config_reader'),
5254
])
5355
->alias(AssetMapperInterface::class, 'asset_mapper')
5456

@@ -76,9 +78,17 @@
7678

7779
->set('asset_mapper.public_assets_path_resolver', PublicAssetsPathResolver::class)
7880
->args([
79-
param('kernel.project_dir'),
8081
abstract_arg('asset public prefix'),
81-
abstract_arg('public directory name'),
82+
])
83+
84+
->set('asset_mapper.local_public_assets_filesystem', LocalPublicAssetsFilesystem::class)
85+
->args([
86+
abstract_arg('public directory'),
87+
])
88+
89+
->set('asset_mapper.compiled_asset_mapper_config_reader', CompiledAssetMapperConfigReader::class)
90+
->args([
91+
abstract_arg('public assets directory'),
8292
])
8393

8494
->set('asset_mapper.asset_package', MapperAwareAssetPackage::class)
@@ -100,12 +110,11 @@
100110

101111
->set('asset_mapper.command.compile', AssetMapperCompileCommand::class)
102112
->args([
103-
service('asset_mapper.public_assets_path_resolver'),
113+
service('asset_mapper.compiled_asset_mapper_config_reader'),
104114
service('asset_mapper'),
105115
service('asset_mapper.importmap.generator'),
106-
service('filesystem'),
116+
service('asset_mapper.local_public_assets_filesystem'),
107117
param('kernel.project_dir'),
108-
abstract_arg('public directory name'),
109118
param('kernel.debug'),
110119
service('event_dispatcher')->nullOnInvalid(),
111120
])
@@ -163,7 +172,7 @@
163172
->set('asset_mapper.importmap.generator', ImportMapGenerator::class)
164173
->args([
165174
service('asset_mapper'),
166-
service('asset_mapper.public_assets_path_resolver'),
175+
service('asset_mapper.compiled_asset_mapper_config_reader'),
167176
service('asset_mapper.importmap.config_reader'),
168177
])
169178

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public function testAssetMapper()
7979
$container = $this->createContainerFromFile('asset_mapper');
8080

8181
$definition = $container->getDefinition('asset_mapper.public_assets_path_resolver');
82-
$this->assertSame('/assets_path/', $definition->getArgument(1));
82+
$this->assertSame('/assets_path/', $definition->getArgument(0));
8383

8484
$definition = $container->getDefinition('asset_mapper.dev_server_subscriber');
8585
$this->assertSame(['zip' => 'application/zip'], $definition->getArgument(2));

src/Symfony/Component/AssetMapper/AssetMapper.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\AssetMapper;
1313

1414
use Symfony\Component\AssetMapper\Factory\MappedAssetFactoryInterface;
15-
use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolverInterface;
1615

1716
/**
1817
* Finds and returns assets in the pipeline.
@@ -28,7 +27,7 @@ class AssetMapper implements AssetMapperInterface
2827
public function __construct(
2928
private readonly AssetMapperRepository $mapperRepository,
3029
private readonly MappedAssetFactoryInterface $mappedAssetFactory,
31-
private readonly PublicAssetsPathResolverInterface $assetsPathResolver,
30+
private readonly CompiledAssetMapperConfigReader $compiledConfigReader,
3231
) {
3332
}
3433

@@ -78,12 +77,10 @@ public function getPublicPath(string $logicalPath): ?string
7877
private function loadManifest(): array
7978
{
8079
if (null === $this->manifestData) {
81-
$path = $this->assetsPathResolver->getPublicFilesystemPath().'/'.self::MANIFEST_FILE_NAME;
82-
83-
if (!is_file($path)) {
80+
if (!$this->compiledConfigReader->configExists(self::MANIFEST_FILE_NAME)) {
8481
$this->manifestData = [];
8582
} else {
86-
$this->manifestData = json_decode(file_get_contents($path), true);
83+
$this->manifestData = $this->compiledConfigReader->loadConfig(self::MANIFEST_FILE_NAME);
8784
}
8885
}
8986

src/Symfony/Component/AssetMapper/Command/AssetMapperCompileCommand.php

Lines changed: 26 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@
1313

1414
use Symfony\Component\AssetMapper\AssetMapper;
1515
use Symfony\Component\AssetMapper\AssetMapperInterface;
16+
use Symfony\Component\AssetMapper\CompiledAssetMapperConfigReader;
1617
use Symfony\Component\AssetMapper\Event\PreAssetsCompileEvent;
1718
use Symfony\Component\AssetMapper\ImportMap\ImportMapGenerator;
1819
use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolverInterface;
20+
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
21+
use Symfony\Component\AssetMapper\Path\PublicAssetsFilesystemInterface;
1922
use Symfony\Component\Console\Attribute\AsCommand;
2023
use Symfony\Component\Console\Command\Command;
21-
use Symfony\Component\Console\Exception\InvalidArgumentException;
2224
use Symfony\Component\Console\Input\InputInterface;
2325
use Symfony\Component\Console\Output\OutputInterface;
2426
use Symfony\Component\Console\Style\SymfonyStyle;
25-
use Symfony\Component\Filesystem\Filesystem;
2627
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
2728

2829
/**
@@ -36,12 +37,11 @@
3637
final class AssetMapperCompileCommand extends Command
3738
{
3839
public function __construct(
39-
private readonly PublicAssetsPathResolverInterface $publicAssetsPathResolver,
40+
private readonly CompiledAssetMapperConfigReader $compiledConfigReader,
4041
private readonly AssetMapperInterface $assetMapper,
4142
private readonly ImportMapGenerator $importMapGenerator,
42-
private readonly Filesystem $filesystem,
43+
private readonly PublicAssetsFilesystemInterface $assetsFilesystem,
4344
private readonly string $projectDir,
44-
private readonly string $publicDirName,
4545
private readonly bool $isDebug,
4646
private readonly ?EventDispatcherInterface $eventDispatcher = null,
4747
) {
@@ -51,7 +51,6 @@ public function __construct(
5151
protected function configure(): void
5252
{
5353
$this
54-
->addOption('clean', null, null, 'Whether to clean the public directory before compiling assets')
5554
->setHelp(<<<'EOT'
5655
The <info>%command.name%</info> command compiles and dumps all the assets in
5756
the asset mapper into the final public directory (usually <comment>public/assets</comment>).
@@ -64,61 +63,36 @@ protected function configure(): void
6463
protected function execute(InputInterface $input, OutputInterface $output): int
6564
{
6665
$io = new SymfonyStyle($input, $output);
67-
$publicDir = $this->projectDir.'/'.$this->publicDirName;
68-
if (!is_dir($publicDir)) {
69-
throw new InvalidArgumentException(sprintf('The public directory "%s" does not exist.', $publicDir));
70-
}
71-
72-
$outputDir = $this->publicAssetsPathResolver->getPublicFilesystemPath();
73-
if ($input->getOption('clean')) {
74-
$io->comment(sprintf('Cleaning <info>%s</info>', $outputDir));
75-
$this->filesystem->remove($outputDir);
76-
$this->filesystem->mkdir($outputDir);
77-
}
78-
79-
// set up the file paths
80-
$files = [];
81-
$manifestPath = $outputDir.'/'.AssetMapper::MANIFEST_FILE_NAME;
82-
$files[] = $manifestPath;
8366

84-
$importMapPath = $outputDir.'/'.ImportMapGenerator::IMPORT_MAP_CACHE_FILENAME;
85-
$files[] = $importMapPath;
67+
$this->eventDispatcher?->dispatch(new PreAssetsCompileEvent($output));
8668

87-
$entrypointFilePaths = [];
69+
// remove existing config files
70+
$this->compiledConfigReader->removeConfig(AssetMapper::MANIFEST_FILE_NAME);
71+
$this->compiledConfigReader->removeConfig(ImportMapGenerator::IMPORT_MAP_CACHE_FILENAME);
72+
$entrypointFiles = [];
8873
foreach ($this->importMapGenerator->getEntrypointNames() as $entrypointName) {
89-
$dumpedEntrypointPath = $outputDir.'/'.sprintf(ImportMapGenerator::ENTRYPOINT_CACHE_FILENAME_PATTERN, $entrypointName);
90-
$files[] = $dumpedEntrypointPath;
91-
$entrypointFilePaths[$entrypointName] = $dumpedEntrypointPath;
74+
$path = sprintf(ImportMapGenerator::ENTRYPOINT_CACHE_FILENAME_PATTERN, $entrypointName);
75+
$this->compiledConfigReader->removeConfig($path);
76+
$entrypointFiles[$entrypointName] = $path;
9277
}
9378

94-
// remove existing files
95-
foreach ($files as $file) {
96-
if (is_file($file)) {
97-
$this->filesystem->remove($file);
98-
}
99-
}
100-
101-
$this->eventDispatcher?->dispatch(new PreAssetsCompileEvent($outputDir, $output));
102-
103-
// dump new files
104-
$manifest = $this->createManifestAndWriteFiles($io, $publicDir);
105-
$this->filesystem->dumpFile($manifestPath, json_encode($manifest, \JSON_PRETTY_PRINT));
79+
$manifest = $this->createManifestAndWriteFiles($io);
80+
$manifestPath = $this->compiledConfigReader->saveConfig(AssetMapper::MANIFEST_FILE_NAME, $manifest);
10681
$io->comment(sprintf('Manifest written to <info>%s</info>', $this->shortenPath($manifestPath)));
10782

108-
$this->filesystem->dumpFile($importMapPath, json_encode($this->importMapGenerator->getRawImportMapData(), \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG));
83+
$importMapPath = $this->compiledConfigReader->saveConfig(ImportMapGenerator::IMPORT_MAP_CACHE_FILENAME, $this->importMapGenerator->getRawImportMapData());
10984
$io->comment(sprintf('Import map data written to <info>%s</info>.', $this->shortenPath($importMapPath)));
11085

111-
$entrypointNames = $this->importMapGenerator->getEntrypointNames();
112-
foreach ($entrypointFilePaths as $entrypointName => $path) {
113-
$this->filesystem->dumpFile($path, json_encode($this->importMapGenerator->findEagerEntrypointImports($entrypointName), \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG));
86+
foreach ($entrypointFiles as $entrypointName => $path) {
87+
$this->compiledConfigReader->saveConfig($path, $this->importMapGenerator->findEagerEntrypointImports($entrypointName));
11488
}
115-
$styledEntrypointNames = array_map(fn (string $entrypointName) => sprintf('<info>%s</>', $entrypointName), $entrypointNames);
116-
$io->comment(sprintf('Entrypoint metadata written for <comment>%d</> entrypoints (%s).', \count($entrypointNames), implode(', ', $styledEntrypointNames)));
89+
$styledEntrypointNames = array_map(fn (string $entrypointName) => sprintf('<info>%s</>', $entrypointName), array_keys($entrypointFiles));
90+
$io->comment(sprintf('Entrypoint metadata written for <comment>%d</> entrypoints (%s).', \count($entrypointFiles), implode(', ', $styledEntrypointNames)));
11791

11892
if ($this->isDebug) {
11993
$io->warning(sprintf(
120-
'You are compiling assets in development. Symfony will not serve any changed assets until you delete the "%s" directory.',
121-
$this->shortenPath($outputDir)
94+
'You are compiling assets in development. Symfony will not serve any changed assets until you delete the files in the "%s" directory.',
95+
$this->shortenPath(\dirname($manifestPath))
12296
));
12397
}
12498

@@ -130,20 +104,18 @@ private function shortenPath(string $path): string
130104
return str_replace($this->projectDir.'/', '', $path);
131105
}
132106

133-
private function createManifestAndWriteFiles(SymfonyStyle $io, string $publicDir): array
107+
private function createManifestAndWriteFiles(SymfonyStyle $io): array
134108
{
135109
$allAssets = $this->assetMapper->allAssets();
136110

137-
$io->comment(sprintf('Compiling assets to <info>%s%s</info>', $publicDir, $this->publicAssetsPathResolver->resolvePublicPath('')));
111+
$io->comment(sprintf('Compiling and writing asset files to <info>%s</info>', $this->shortenPath($this->assetsFilesystem->getDestinationPath())));
138112
$manifest = [];
139113
foreach ($allAssets as $asset) {
140-
// $asset->getPublicPath() will start with a "/"
141-
$targetPath = $publicDir.$asset->publicPath;
142114
if (null !== $asset->content) {
143115
// The original content has been modified by the AssetMapperCompiler
144-
$this->filesystem->dumpFile($targetPath, $asset->content);
116+
$this->assetsFilesystem->write($asset->publicPath, $asset->content);
145117
} else {
146-
$this->filesystem->copy($asset->sourcePath, $targetPath, true);
118+
$this->assetsFilesystem->copy($asset->sourcePath, $asset->publicPath);
147119
}
148120

149121
$manifest[$asset->logicalPath] = $asset->publicPath;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\AssetMapper;
13+
14+
use Symfony\Component\Filesystem\Path;
15+
16+
/**
17+
* Reads and writes compiled configuration files for asset mapper.
18+
*/
19+
class CompiledAssetMapperConfigReader
20+
{
21+
public function __construct(private readonly string $directory)
22+
{
23+
}
24+
25+
public function configExists(string $filename): bool
26+
{
27+
return is_file(Path::join($this->directory, $filename));
28+
}
29+
30+
public function loadConfig(string $filename): array
31+
{
32+
return json_decode(file_get_contents(Path::join($this->directory, $filename)), true, 512, \JSON_THROW_ON_ERROR);
33+
}
34+
35+
public function saveConfig(string $filename, array $data): string
36+
{
37+
$path = Path::join($this->directory, $filename);
38+
@mkdir(\dirname($path), 0777, true);
39+
file_put_contents($path, json_encode($data, \JSON_PRETTY_PRINT | \JSON_THROW_ON_ERROR));
40+
41+
return $path;
42+
}
43+
44+
public function removeConfig(string $filename): void
45+
{
46+
$path = Path::join($this->directory, $filename);
47+
48+
if (is_file($path)) {
49+
unlink($path);
50+
}
51+
}
52+
}

src/Symfony/Component/AssetMapper/Event/PreAssetsCompileEvent.php

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,13 @@
2121
*/
2222
class PreAssetsCompileEvent extends Event
2323
{
24-
private string $outputDir;
2524
private OutputInterface $output;
2625

27-
public function __construct(string $outputDir, OutputInterface $output)
26+
public function __construct(OutputInterface $output)
2827
{
29-
$this->outputDir = $outputDir;
3028
$this->output = $output;
3129
}
3230

33-
public function getOutputDir(): string
34-
{
35-
return $this->outputDir;
36-
}
37-
3831
public function getOutput(): OutputInterface
3932
{
4033
return $this->output;

0 commit comments

Comments
 (0)
0