• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

heimrichhannot / contao-encore-bundle / 4606513634

pending completion
4606513634

push

github

Thomas Körner
optimized errors in prepare command

24 of 24 new or added lines in 1 file covered. (100.0%)

622 of 829 relevant lines covered (75.03%)

1.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Command/PrepareCommand.php
1
<?php
2

3
/*
4
 * Copyright (c) 2023 Heimrich & Hannot GmbH
5
 *
6
 * @license LGPL-3.0-or-later
7
 */
8

9
namespace HeimrichHannot\EncoreBundle\Command;
10

11
use Composer\InstalledVersions;
12
use const DIRECTORY_SEPARATOR;
13
use HeimrichHannot\EncoreBundle\Collection\ExtensionCollection;
14
use Psr\Cache\CacheItemPoolInterface;
15
use Symfony\Component\Console\Command\Command;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Input\InputOption;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Style\SymfonyStyle;
20
use Symfony\Component\Filesystem\Filesystem;
21
use Symfony\Component\HttpKernel\KernelInterface;
22
use Twig\Environment;
23

24
class PrepareCommand extends Command
25
{
26
    public const DEPENDENCY_PREFIX = '@huh/encore-bundle--';
27

28
    protected static $defaultName = 'huh:encore:prepare';
29
    protected static $defaultDescription = 'Does the necessary preparation for contao encore bundle. Needs to be called after changes to bundle encore entries.';
30

31
    private SymfonyStyle           $io;
32
    private CacheItemPoolInterface $encoreCache;
33
    private KernelInterface        $kernel;
34
    private array                  $bundleConfig;
35
    private Environment            $twig;
36
    private ExtensionCollection    $extensionCollection;
37

38
    public function __construct(CacheItemPoolInterface $encoreCache, KernelInterface $kernel, array $bundleConfig, Environment $twig, ExtensionCollection $extensionCollection)
39
    {
40
        parent::__construct();
×
41

42
        $this->encoreCache = $encoreCache;
×
43
        $this->kernel = $kernel;
×
44
        $this->bundleConfig = $bundleConfig;
×
45
        $this->twig = $twig;
×
46
        $this->extensionCollection = $extensionCollection;
×
47
    }
48

49
    /**
50
     * {@inheritdoc}
51
     */
52
    protected function configure()
53
    {
54
        $this->setAliases(['encore:prepare'])
×
55
            ->setDescription(static::$defaultDescription)
×
56
            ->addOption('skip-entries', null, InputOption::VALUE_OPTIONAL, 'Add a comma separated list of entries to skip their generation.', false);
×
57
    }
58

59
    /**
60
     * {@inheritdoc}
61
     */
62
    protected function execute(InputInterface $input, OutputInterface $output)
63
    {
64
        $this->io = new SymfonyStyle($input, $output);
×
65

66
        $this->io->title('Update project encore data');
×
67

68
        $resultFile = $this->kernel->getProjectDir().DIRECTORY_SEPARATOR.'encore.bundles.js';
×
69

70
        $skipEntries = $input->getOption('skip-entries') ? explode(',', $input->getOption('skip-entries')) : [];
×
71

72
        $this->io->writeln('Using <fg=green>'.$this->kernel->getEnvironment().'</> environment. (Use --env=[ENV] to change environment. See --help for more information!)');
×
73

74
        @unlink($resultFile);
×
75

76
        $this->encoreCache->clear();
×
77

78
        $this->io->text(['', ' // Collect entries', '']);
×
79

80
        $this->io->writeln('> Collect entries from yaml config');
×
81

82
        $encoreJsEntries = [];
×
83

84
        // collect entries from yaml
85
        if (isset($this->bundleConfig['js_entries']) && \is_array($this->bundleConfig['js_entries'])) {
×
86
            foreach ($this->bundleConfig['js_entries'] as $entry) {
×
87
                $preparedEntry = [
×
88
                    'name' => $entry['name'],
×
89
                ];
×
90

91
                if (!str_starts_with($entry['file'], '@')) {
×
92
                    $preparedEntry['file'] = './'.preg_replace('@^\.?\/@i', '', $entry['file']);
×
93
                } else {
94
                    $preparedEntry['file'] = rtrim((new Filesystem())->makePathRelative($this->kernel->locateResource($entry['file']), $this->kernel->getProjectDir()), DIRECTORY_SEPARATOR);
×
95
                }
96
                $encoreJsEntries[] = $preparedEntry;
×
97
            }
98
        }
99

100
        $this->io->newLine();
×
101
        $yamlEntryCount = \count($encoreJsEntries);
×
102
        if ($yamlEntryCount < 1) {
×
103
            $this->io->writeln('Found no encore entry registered through yaml config 👍');
×
104
        } elseif (1 === $yamlEntryCount) {
×
105
            $this->io->writeln('<bg=yellow;fg=black>Found 1 encore entry registered through yaml config. This is deprecated and support will be dropped in a future version.</>');
×
106
        } else {
107
            $this->io->writeln("<bg=yellow;fg=black>Found $yamlEntryCount encore entries registered through yaml config. This is deprecated and support will be dropped in a future version.</>");
×
108
        }
109

110
        if ($this->io->isVerbose()) {
×
111
            $this->io->text(['', 'Following entries registered through yaml:']);
×
112
            $this->io->table(['name', 'path'], $encoreJsEntries);
×
113
        }
114

115
        $this->io->writeln(['', '> Collect entries from encore extensions']);
×
116
        $extensionDependencies = [];
×
117
        $extensionList = [];
×
118

119
        foreach ($this->extensionCollection->getExtensions() as $extension) {
×
120
            $reflection = new \ReflectionClass($extension->getBundle());
×
121
            $bundle = $this->kernel->getBundles()[$reflection->getShortName()];
×
122
            $bundlePath = $bundle->getPath();
×
123
            if (!file_exists($bundlePath.DIRECTORY_SEPARATOR.'composer.json')) {
×
124
                $bundlePath = $bundlePath.DIRECTORY_SEPARATOR.'..';
×
125
            }
126
            if (!file_exists($bundlePath.DIRECTORY_SEPARATOR.'composer.json')) {
×
127
                trigger_error(
×
128
                    '[Encore Bundle] Could not find composer.json file for '.$bundle->getName().'.'
×
129
                    .' Skipping EncoreExtension '.\get_class($extension).'.'
×
130
                );
×
131
                continue;
×
132
            }
133

134
            try {
135
                $composerData = json_decode(file_get_contents($bundlePath.'/composer.json'), null, 512, \JSON_THROW_ON_ERROR);
×
136
            } catch (\JsonException $e) {
×
137
                throw new \JsonException('composer.json of '.$reflection->getShortName().' has a syntax error.');
×
138
            }
139

140
            $bundlePath = InstalledVersions::getInstallPath($composerData->name);
×
141

142
            $bundlePath = rtrim((new Filesystem())->makePathRelative($bundlePath, $this->kernel->getProjectDir()), DIRECTORY_SEPARATOR);
×
143

144
            $preparedEntry = [];
×
145
            foreach ($extension->getEntries() as $entry) {
×
146
                $preparedEntry['name'] = $entry->getName();
×
147
                $preparedEntry['file'] = '.'.DIRECTORY_SEPARATOR.$bundlePath.DIRECTORY_SEPARATOR.ltrim($entry->getPath(), DIRECTORY_SEPARATOR);
×
148
                $encoreJsEntries[] = $preparedEntry;
×
149
            }
150

151
            if (file_exists($bundlePath.DIRECTORY_SEPARATOR.'package.json')) {
×
152
                $packageData = json_decode(file_get_contents($bundlePath.DIRECTORY_SEPARATOR.'package.json'), true);
×
153
                $extensionDependencies = array_merge($extensionDependencies, ($packageData['dependencies'] ?? []));
×
154
            }
155

156
            $extensionList[] = [$reflection->getShortName(), \get_class($extension), $bundlePath];
×
157
        }
158

159
        $this->io->newLine();
×
160
        $this->io->writeln('Found <fg=green>'.\count($this->extensionCollection->getExtensions()).'</> registered encore extensions.');
×
161

162
        if ($this->io->isVerbose()) {
×
163
            $this->io->table(['Bundle', 'Extension', 'Bundle path'], $extensionList);
×
164
        }
165

166
        $this->io->text(['', ' // Update encore entry dependencies', '']);
×
167

168
        $projectPackageJsonPath = $this->kernel->getProjectDir().DIRECTORY_SEPARATOR.'package.json';
×
169
        if (!file_exists($projectPackageJsonPath)) {
×
170
            throw new \Exception('No package.json could be found in your project. This file must be present for encore to work!');
×
171
        }
172

173
        $this->io->writeln('Collect encore entry dependencies ');
×
174
        $encorePackageData = [
×
175
            'name' => '@hundh/encore-entry-dependencies',
×
176
            'version' => date('Ymd').'.'.date('Hi').'.'.time(),
×
177
            'dependencies' => $extensionDependencies,
×
178
        ];
×
179
        $encoreAssetsPath = 'vendor'.DIRECTORY_SEPARATOR.'heimrichhannot'.DIRECTORY_SEPARATOR.'encore-entry-dependencies';
×
180

181
        (new Filesystem())->dumpFile(
×
182
            $this->kernel->getProjectDir().DIRECTORY_SEPARATOR.$encoreAssetsPath.DIRECTORY_SEPARATOR.'package.json',
×
183
            json_encode($encorePackageData, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)
×
184
        );
×
185

186
        $this->io->writeln('Register dependencies in project');
×
187
        $packageData = json_decode(file_get_contents($projectPackageJsonPath), true, 512, \JSON_THROW_ON_ERROR);
×
188

189
        $packageData['dependencies'] = array_merge(
×
190
            ['@hundh/encore-entry-dependencies' => 'file:.'.DIRECTORY_SEPARATOR.$encoreAssetsPath.DIRECTORY_SEPARATOR],
×
191
            $packageData['dependencies'] ?? []
×
192
        );
×
193

194
        (new Filesystem())->dumpFile(
×
195
            $projectPackageJsonPath,
×
196
            json_encode($packageData, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)
×
197
        );
×
198

199
        if (!empty($encoreJsEntries)) {
×
200
            $this->io->text(['', ' // Output encore_bundles.js', '']);
×
201

202
            $content = $this->twig->render('@HeimrichHannotContaoEncore/encore_bundles.js.twig', [
×
203
                'entries' => $encoreJsEntries,
×
204
                'skipEntries' => $skipEntries,
×
205
            ]);
×
206

207
            file_put_contents($resultFile, $content);
×
208

209
            $this->io->writeln('Created encore.bundles.js in your project root. You can now require it in your webpack.config.js');
×
210
        } else {
211
            $this->io->warning('Found no registered encore entries. Skipped encore.bundles.js creation.');
×
212
        }
213

214
        $this->io->success('Finished updating your project encore data.');
×
215

216
        $this->io->text([
×
217
            'Next steps:',
×
218
            '1. If your dependencies have changed, run <fg=black;bg=cyan> yarn upgrade </>.',
×
219
            '2. Compile your asset with <fg=black;bg=cyan> yarn encore dev </>, <fg=black;bg=cyan> yarn encore dev --watch </> or <fg=black;bg=cyan> yarn encore prod </>',
×
220
            '',
×
221
        ]);
×
222

223
        return 0;
×
224
    }
225
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc