Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 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\Console\Descriptor;
13
 
14
use Symfony\Component\Console\Application;
15
use Symfony\Component\Console\Command\Command;
16
use Symfony\Component\Console\Formatter\OutputFormatter;
17
use Symfony\Component\Console\Helper\Helper;
18
use Symfony\Component\Console\Input\InputArgument;
19
use Symfony\Component\Console\Input\InputDefinition;
20
use Symfony\Component\Console\Input\InputOption;
21
 
22
/**
23
 * Text descriptor.
24
 *
25
 * @author Jean-François Simon <contact@jfsimon.fr>
26
 *
27
 * @internal
28
 */
29
class TextDescriptor extends Descriptor
30
{
31
    protected function describeInputArgument(InputArgument $argument, array $options = [])
32
    {
33
        if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
34
            $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
35
        } else {
36
            $default = '';
37
        }
38
 
39
        $totalWidth = $options['total_width'] ?? Helper::width($argument->getName());
40
        $spacingWidth = $totalWidth - \strlen($argument->getName());
41
 
42
        $this->writeText(sprintf('  <info>%s</info>  %s%s%s',
43
            $argument->getName(),
44
            str_repeat(' ', $spacingWidth),
45
            // + 4 = 2 spaces before <info>, 2 spaces after </info>
46
            preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
47
            $default
48
        ), $options);
49
    }
50
 
51
    protected function describeInputOption(InputOption $option, array $options = [])
52
    {
53
        if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
54
            $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
55
        } else {
56
            $default = '';
57
        }
58
 
59
        $value = '';
60
        if ($option->acceptValue()) {
61
            $value = '='.strtoupper($option->getName());
62
 
63
            if ($option->isValueOptional()) {
64
                $value = '['.$value.']';
65
            }
66
        }
67
 
68
        $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
69
        $synopsis = sprintf('%s%s',
70
            $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : '    ',
71
            sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)
72
        );
73
 
74
        $spacingWidth = $totalWidth - Helper::width($synopsis);
75
 
76
        $this->writeText(sprintf('  <info>%s</info>  %s%s%s%s',
77
            $synopsis,
78
            str_repeat(' ', $spacingWidth),
79
            // + 4 = 2 spaces before <info>, 2 spaces after </info>
80
            preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
81
            $default,
82
            $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
83
        ), $options);
84
    }
85
 
86
    protected function describeInputDefinition(InputDefinition $definition, array $options = [])
87
    {
88
        $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
89
        foreach ($definition->getArguments() as $argument) {
90
            $totalWidth = max($totalWidth, Helper::width($argument->getName()));
91
        }
92
 
93
        if ($definition->getArguments()) {
94
            $this->writeText('<comment>Arguments:</comment>', $options);
95
            $this->writeText("\n");
96
            foreach ($definition->getArguments() as $argument) {
97
                $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));
98
                $this->writeText("\n");
99
            }
100
        }
101
 
102
        if ($definition->getArguments() && $definition->getOptions()) {
103
            $this->writeText("\n");
104
        }
105
 
106
        if ($definition->getOptions()) {
107
            $laterOptions = [];
108
 
109
            $this->writeText('<comment>Options:</comment>', $options);
110
            foreach ($definition->getOptions() as $option) {
111
                if (\strlen($option->getShortcut() ?? '') > 1) {
112
                    $laterOptions[] = $option;
113
                    continue;
114
                }
115
                $this->writeText("\n");
116
                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
117
            }
118
            foreach ($laterOptions as $option) {
119
                $this->writeText("\n");
120
                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
121
            }
122
        }
123
    }
124
 
125
    protected function describeCommand(Command $command, array $options = [])
126
    {
127
        $command->mergeApplicationDefinition(false);
128
 
129
        if ($description = $command->getDescription()) {
130
            $this->writeText('<comment>Description:</comment>', $options);
131
            $this->writeText("\n");
132
            $this->writeText('  '.$description);
133
            $this->writeText("\n\n");
134
        }
135
 
136
        $this->writeText('<comment>Usage:</comment>', $options);
137
        foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {
138
            $this->writeText("\n");
139
            $this->writeText('  '.OutputFormatter::escape($usage), $options);
140
        }
141
        $this->writeText("\n");
142
 
143
        $definition = $command->getDefinition();
144
        if ($definition->getOptions() || $definition->getArguments()) {
145
            $this->writeText("\n");
146
            $this->describeInputDefinition($definition, $options);
147
            $this->writeText("\n");
148
        }
149
 
150
        $help = $command->getProcessedHelp();
151
        if ($help && $help !== $description) {
152
            $this->writeText("\n");
153
            $this->writeText('<comment>Help:</comment>', $options);
154
            $this->writeText("\n");
155
            $this->writeText('  '.str_replace("\n", "\n  ", $help), $options);
156
            $this->writeText("\n");
157
        }
158
    }
159
 
160
    protected function describeApplication(Application $application, array $options = [])
161
    {
162
        $describedNamespace = $options['namespace'] ?? null;
163
        $description = new ApplicationDescription($application, $describedNamespace);
164
 
165
        if (isset($options['raw_text']) && $options['raw_text']) {
166
            $width = $this->getColumnWidth($description->getCommands());
167
 
168
            foreach ($description->getCommands() as $command) {
169
                $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
170
                $this->writeText("\n");
171
            }
172
        } else {
173
            if ('' != $help = $application->getHelp()) {
174
                $this->writeText("$help\n\n", $options);
175
            }
176
 
177
            $this->writeText("<comment>Usage:</comment>\n", $options);
178
            $this->writeText("  command [options] [arguments]\n\n", $options);
179
 
180
            $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);
181
 
182
            $this->writeText("\n");
183
            $this->writeText("\n");
184
 
185
            $commands = $description->getCommands();
186
            $namespaces = $description->getNamespaces();
187
            if ($describedNamespace && $namespaces) {
188
                // make sure all alias commands are included when describing a specific namespace
189
                $describedNamespaceInfo = reset($namespaces);
190
                foreach ($describedNamespaceInfo['commands'] as $name) {
191
                    $commands[$name] = $description->getCommand($name);
192
                }
193
            }
194
 
195
            // calculate max. width based on available commands per namespace
196
            $width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) {
197
                return array_intersect($namespace['commands'], array_keys($commands));
198
            }, array_values($namespaces)))));
199
 
200
            if ($describedNamespace) {
201
                $this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
202
            } else {
203
                $this->writeText('<comment>Available commands:</comment>', $options);
204
            }
205
 
206
            foreach ($namespaces as $namespace) {
207
                $namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) {
208
                    return isset($commands[$name]);
209
                });
210
 
211
                if (!$namespace['commands']) {
212
                    continue;
213
                }
214
 
215
                if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
216
                    $this->writeText("\n");
217
                    $this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);
218
                }
219
 
220
                foreach ($namespace['commands'] as $name) {
221
                    $this->writeText("\n");
222
                    $spacingWidth = $width - Helper::width($name);
223
                    $command = $commands[$name];
224
                    $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
225
                    $this->writeText(sprintf('  <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options);
226
                }
227
            }
228
 
229
            $this->writeText("\n");
230
        }
231
    }
232
 
233
    private function writeText(string $content, array $options = [])
234
    {
235
        $this->write(
236
            isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
237
            isset($options['raw_output']) ? !$options['raw_output'] : true
238
        );
239
    }
240
 
241
    /**
242
     * Formats command aliases to show them in the command description.
243
     */
244
    private function getCommandAliasesText(Command $command): string
245
    {
246
        $text = '';
247
        $aliases = $command->getAliases();
248
 
249
        if ($aliases) {
250
            $text = '['.implode('|', $aliases).'] ';
251
        }
252
 
253
        return $text;
254
    }
255
 
256
    /**
257
     * Formats input option/argument default value.
258
     */
259
    private function formatDefaultValue(mixed $default): string
260
    {
261
        if (\INF === $default) {
262
            return 'INF';
263
        }
264
 
265
        if (\is_string($default)) {
266
            $default = OutputFormatter::escape($default);
267
        } elseif (\is_array($default)) {
268
            foreach ($default as $key => $value) {
269
                if (\is_string($value)) {
270
                    $default[$key] = OutputFormatter::escape($value);
271
                }
272
            }
273
        }
274
 
275
        return str_replace('\\\\', '\\', json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
276
    }
277
 
278
    /**
279
     * @param array<Command|string> $commands
280
     */
281
    private function getColumnWidth(array $commands): int
282
    {
283
        $widths = [];
284
 
285
        foreach ($commands as $command) {
286
            if ($command instanceof Command) {
287
                $widths[] = Helper::width($command->getName());
288
                foreach ($command->getAliases() as $alias) {
289
                    $widths[] = Helper::width($alias);
290
                }
291
            } else {
292
                $widths[] = Helper::width($command);
293
            }
294
        }
295
 
296
        return $widths ? max($widths) + 2 : 0;
297
    }
298
 
299
    /**
300
     * @param InputOption[] $options
301
     */
302
    private function calculateTotalWidthForOptions(array $options): int
303
    {
304
        $totalWidth = 0;
305
        foreach ($options as $option) {
306
            // "-" + shortcut + ", --" + name
307
            $nameLength = 1 + max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName());
308
            if ($option->isNegatable()) {
309
                $nameLength += 6 + Helper::width($option->getName()); // |--no- + name
310
            } elseif ($option->acceptValue()) {
311
                $valueLength = 1 + Helper::width($option->getName()); // = + value
312
                $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ]
313
 
314
                $nameLength += $valueLength;
315
            }
316
            $totalWidth = max($totalWidth, $nameLength);
317
        }
318
 
319
        return $totalWidth;
320
    }
321
}