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

CPS-IT / frontend-asset-handler / 15251341592

26 May 2025 10:12AM UTC coverage: 99.233%. Remained the same
15251341592

Pull #659

github

web-flow
Merge c6e7b1587 into 8b95d2cff
Pull Request #659: [TASK] Update phpunit/phpunit to v12

2459 of 2478 relevant lines covered (99.23%)

15.09 hits per line

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

95.52
/src/Console/Application.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "cpsit/frontend-asset-handler".
7
 *
8
 * Copyright (C) 2022 Elias Häußler <e.haeussler@familie-redlich.de>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace CPSIT\FrontendAssetHandler\Console;
25

26
use Composer\InstalledVersions;
27
use CPSIT\FrontendAssetHandler\Command;
28
use CPSIT\FrontendAssetHandler\DependencyInjection;
29
use CPSIT\FrontendAssetHandler\Helper\FilesystemHelper;
30
use OutOfBoundsException;
31
use Symfony\Component\Console;
32
use Symfony\Component\DependencyInjection as SymfonyDI;
33

34
use function in_array;
35

36
/**
37
 * Application.
38
 *
39
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
40
 * @license GPL-3.0-or-later
41
 *
42
 * @internal
43
 */
44
final class Application extends Console\Application
45
{
46
    private const FAILSAFE_COMMANDS = [
47
        'cc',
48
        'clear-cache',
49
        'help',
50
        'init',
51
        'list',
52
    ];
53

54
    private Console\Input\InputInterface $input;
55
    private ?SymfonyDI\ContainerInterface $failsafeContainer = null;
56
    private ?SymfonyDI\ContainerInterface $container = null;
57
    private bool $commandsAdded = false;
58

59
    public function __construct()
10✔
60
    {
61
        parent::__construct('Frontend Asset Handler', $this->determineCurrentVersion() ?? 'UNKNOWN');
10✔
62
    }
63

64
    protected function getDefaultInputDefinition(): Console\Input\InputDefinition
10✔
65
    {
66
        $inputDefinition = parent::getDefaultInputDefinition();
10✔
67
        $inputDefinition->addOption(
10✔
68
            new Console\Input\InputOption(
10✔
69
                'config',
10✔
70
                'c',
10✔
71
                Console\Input\InputOption::VALUE_REQUIRED,
10✔
72
                'Path to the assets configuration file',
10✔
73
                FilesystemHelper::resolveRelativePath('assets.json'),
10✔
74
            ),
10✔
75
        );
10✔
76

77
        return $inputDefinition;
10✔
78
    }
79

80
    public function doRun(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
10✔
81
    {
82
        $this->input = $input;
10✔
83

84
        return parent::doRun($input, $output);
10✔
85
    }
86

87
    protected function doRunCommand(
10✔
88
        Console\Command\Command $command,
89
        Console\Input\InputInterface $input,
90
        Console\Output\OutputInterface $output,
91
    ): int {
92
        // Show introduction header for all asset commands
93
        if ($command instanceof Command\BaseAssetsCommand || $command instanceof Command\InitConfigCommand) {
10✔
94
            $io = new Console\Style\SymfonyStyle($input, $output);
2✔
95
            $io->section(sprintf('Running <comment>%s</comment>', $this->getLongVersion()));
2✔
96
        }
97

98
        return parent::doRunCommand($command, $input, $output);
10✔
99
    }
100

101
    public function find(string $name): Console\Command\Command
10✔
102
    {
103
        // If only the available commands should be listed, we can safely add
104
        // them from the failsafe container
105
        if ('list' === $name) {
10✔
106
            $this->addAssetCommands(true);
1✔
107
        }
108

109
        // Add only the clear-cache command if it's requested. This way, we can
110
        // avoid issues with a potentially outdated container.
111
        if (in_array($name, ['clear-cache', 'cc'], true)) {
10✔
112
            $this->addClearCacheCommand();
2✔
113
        }
114

115
        try {
116
            return parent::find($name);
10✔
117
        } catch (Console\Exception\CommandNotFoundException) {
7✔
118
            // In case a command was requested that is not yet added to the list of
119
            // available commands, we add them now. If the requested command is
120
            // considered failsafe or the help of a command is requested, we use
121
            // the failsafe container to add commands. This avoids booting up the
122
            // whole container without having a valid config file, which would lead
123
            // to exceptions when initializing the requested command.
124
            $this->addAssetCommands($this->isHelpRequested() || in_array($name, self::FAILSAFE_COMMANDS, true));
7✔
125
        }
126

127
        // Try to find the command again after we've added all available commands
128
        return parent::find($name);
7✔
129
    }
130

131
    private function addAssetCommands(bool $failsafe = false): void
8✔
132
    {
133
        // Early return if commands were already added
134
        if ($this->commandsAdded) {
8✔
135
            return;
×
136
        }
137

138
        if ($failsafe) {
8✔
139
            $container = $this->createFailsafeContainer();
6✔
140
        } else {
141
            $container = $this->createContainer();
2✔
142
        }
143

144
        $this->addClearCacheCommand();
8✔
145
        $this->addCommands([
8✔
146
            $container->get(Command\ConfigAssetsCommand::class),
8✔
147
            $container->get(Command\FetchAssetsCommand::class),
8✔
148
            $container->get(Command\InitConfigCommand::class),
8✔
149
            $container->get(Command\InspectAssetsCommand::class),
8✔
150
        ]);
8✔
151

152
        $this->commandsAdded = true;
8✔
153
    }
154

155
    private function addClearCacheCommand(): void
10✔
156
    {
157
        $this->add($this->createFailsafeContainer()->get(Command\ClearCacheCommand::class));
10✔
158
    }
159

160
    private function isHelpRequested(): bool
7✔
161
    {
162
        return $this->input->hasParameterOption(['--help', '-h'], true);
7✔
163
    }
164

165
    private function createContainer(): SymfonyDI\ContainerInterface
2✔
166
    {
167
        if (null === $this->container) {
2✔
168
            $temporaryInput = clone $this->input;
2✔
169
            $temporaryInput->bind($this->getDefinition());
2✔
170
            $containerFactory = new DependencyInjection\ContainerFactory($temporaryInput->getOption('config'));
2✔
171
            $this->container = $containerFactory->get();
2✔
172
        }
173

174
        return $this->container;
2✔
175
    }
176

177
    private function createFailsafeContainer(): SymfonyDI\ContainerInterface
10✔
178
    {
179
        if (null === $this->failsafeContainer) {
10✔
180
            $containerFactory = new DependencyInjection\ContainerFactory();
10✔
181
            $this->failsafeContainer = $containerFactory->get();
10✔
182
        }
183

184
        return $this->failsafeContainer;
10✔
185
    }
186

187
    public function getLongVersion(): string
3✔
188
    {
189
        return parent::getLongVersion().' <bg=blue;fg=white>#StandWith</><bg=yellow;fg=black>Ukraine</>';
3✔
190
    }
191

192
    private function determineCurrentVersion(): ?string
10✔
193
    {
194
        try {
195
            return InstalledVersions::getPrettyVersion('cpsit/frontend-asset-handler');
10✔
196
        } catch (OutOfBoundsException) {
×
197
            return null;
×
198
        }
199
    }
200
}
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