Completed
Push — master ( 303d3b...22ea3e )
by Greg
07:12
created

CommandProcessor::writeUsingFormatter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 4
1
<?php
2
namespace Consolidation\AnnotatedCommand;
3
4
use Symfony\Component\Console\Command\Command;
5
use Symfony\Component\Console\Input\InputInterface;
6
use Symfony\Component\Console\Output\OutputInterface;
7
use Symfony\Component\Console\Output\ConsoleOutputInterface;
8
9
use Consolidation\OutputFormatters\FormatterManager;
10
use Consolidation\OutputFormatters\FormatterOptions;
11
use Consolidation\AnnotatedCommand\Hooks\HookManager;
12
13
/**
14
 * Process a command, including hooks and other callbacks.
15
 * There should only be one command processor per application.
16
 * Provide your command processor to the AnnotatedCommandFactory
17
 * via AnnotatedCommandFactory::setCommandProcessor().
18
 */
19
class CommandProcessor
20
{
21
    /** var HookManager */
22
    protected $hookManager;
23
    /** var FormatterManager */
24
    protected $formatterManager;
25
    /** var callable */
26
    protected $displayErrorFunction;
27
28
    public function __construct(HookManager $hookManager)
29
    {
30
        $this->hookManager = $hookManager;
31
    }
32
33
    /**
34
     * Return the hook manager
35
     * @return HookManager
36
     */
37
    public function hookManager()
38
    {
39
        return $this->hookManager;
40
    }
41
42
    public function setFormatterManager(FormatterManager $formatterManager)
43
    {
44
        $this->formatterManager = $formatterManager;
45
    }
46
47
    public function setDisplayErrorFunction(callable $fn)
48
    {
49
        $this->displayErrorFunction = $fn;
50
    }
51
52
    /**
53
     * Return the formatter manager
54
     * @return FormatterManager
55
     */
56
    public function formatterManager()
57
    {
58
        return $this->formatterManager;
59
    }
60
61
    public function interact(
62
        InputInterface $input,
63
        OutputInterface $output,
64
        $names,
65
        AnnotationData $annotationData
66
    ) {
67
        return $this->hookManager()->interact($input, $output, $names, $annotationData);
68
    }
69
70
    public function process(
71
        OutputInterface $output,
72
        $names,
73
        $commandCallback,
74
        AnnotationData $annotationData,
75
        $args
76
    ) {
77
        $result = [];
78
        // Recover options from the end of the args
79
        $options = end($args);
80
        try {
81
            $result = $this->validateRunAndAlter(
82
                $names,
83
                $commandCallback,
84
                $args,
85
                $annotationData
86
            );
87
            return $this->handleResults($output, $names, $result, $annotationData, $options);
88
        } catch (\Exception $e) {
89
            $result = new CommandError($e->getMessage(), $e->getCode());
90
            return $this->handleResults($output, $names, $result, $annotationData, $options);
91
        }
92
    }
93
94 View Code Duplication
    public function validateRunAndAlter(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
        $names,
96
        $commandCallback,
97
        $args,
98
        AnnotationData $annotationData
99
    ) {
100
        // Validators return any object to signal a validation error;
101
        // if the return an array, it replaces the arguments.
102
        $validated = $this->hookManager()->validateArguments($names, $args, $annotationData);
103
        if (is_object($validated)) {
104
            return $validated;
105
        }
106
        if (is_array($validated)) {
107
            $args = $validated;
108
        }
109
110
        // Run the command, alter the results, and then handle output and status
111
        $result = $this->runCommandCallback($commandCallback, $args);
112
        return $this->processResults($names, $result, $args, $annotationData);
113
    }
114
115
    public function processResults($names, $result, $args, $annotationData)
116
    {
117
        return $this->hookManager()->alterResult($names, $result, $args, $annotationData);
118
    }
119
120
    /**
121
     * Handle the result output and status code calculation.
122
     */
123
    public function handleResults(OutputInterface $output, $names, $result, AnnotationData $annotationData, $options = [])
124
    {
125
        $status = $this->hookManager()->determineStatusCode($names, $result);
126
        // If the result is an integer and no separate status code was provided, then use the result as the status and do no output.
127
        if (is_integer($result) && !isset($status)) {
128
            return $result;
129
        }
130
        $status = $this->interpretStatusCode($status);
131
132
        // Get the structured output, the output stream and the formatter
133
        $structuredOutput = $this->hookManager()->extractOutput($names, $result);
134
        $output = $this->chooseOutputStream($output, $status);
135
        if ($status != 0) {
136
            return $this->writeErrorMessage($output, $status, $structuredOutput, $result);
137
        }
138
        if (isset($this->formatterManager)) {
139
            return $this->writeUsingFormatter($output, $structuredOutput, $annotationData, $options);
140
        }
141
        return $this->writeCommandOutput($output, $structuredOutput);
142
    }
143
144
    /**
145
     * Run the main command callback
146
     */
147
    protected function runCommandCallback($commandCallback, $args)
148
    {
149
        $result = false;
150
        try {
151
            $result = call_user_func_array($commandCallback, $args);
152
        } catch (\Exception $e) {
153
            $result = new CommandError($e->getMessage(), $e->getCode());
154
        }
155
        return $result;
156
    }
157
158
    /**
159
     * Determine the formatter that should be used to render
160
     * output.
161
     *
162
     * If the user specified a format via the --format option,
163
     * then always return that.  Otherwise, return the default
164
     * format, unless --pipe was specified, in which case
165
     * return the default pipe format, format-pipe.
166
     *
167
     * n.b. --pipe is a handy option introduced in Drush 2
168
     * (or perhaps even Drush 1) that indicates that the command
169
     * should select the output format that is most appropriate
170
     * for use in scripts (e.g. to pipe to another command).
171
     *
172
     * @return string
173
     */
174
    protected function getFormat($options)
175
    {
176
        $options += [
177
            'default-format' => false,
178
            'pipe' => false,
179
        ];
180
        $options += [
181
            'format' => $options['default-format'],
182
            'format-pipe' => $options['default-format'],
183
        ];
184
185
        $format = $options['format'];
186
        if ($options['pipe']) {
187
            $format = $options['format-pipe'];
188
        }
189
        return $format;
190
    }
191
192
    /**
193
     * Determine whether we should use stdout or stderr.
194
     */
195
    protected function chooseOutputStream(OutputInterface $output, $status)
196
    {
197
        // If the status code indicates an error, then print the
198
        // result to stderr rather than stdout
199
        if ($status && ($output instanceof ConsoleOutputInterface)) {
200
            return $output->getErrorOutput();
201
        }
202
        return $output;
203
    }
204
205
    /**
206
     * Call the formatter to output the provided data.
207
     */
208
    protected function writeUsingFormatter(OutputInterface $output, $structuredOutput, AnnotationData $annotationData, $options)
209
    {
210
        $format = $this->getFormat($options);
211
        $formatterOptions = new FormatterOptions($annotationData->getArrayCopy(), $options);
212
        $this->formatterManager->write(
213
            $output,
214
            $format,
0 ignored issues
show
Documentation introduced by
$format is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
215
            $structuredOutput,
216
            $formatterOptions
217
        );
218
        return 0;
219
    }
220
221
    /**
222
     * Description
223
     * @param OutputInterface $output
224
     * @param int $status
225
     * @param string $structuredOutput
226
     * @param mixed $originalResult
227
     * @return type
228
     */
229
    protected function writeErrorMessage($output, $status, $structuredOutput, $originalResult)
230
    {
231
        if (isset($this->displayErrorFunction)) {
232
            call_user_func($this->displayErrorFunction, $output, $structuredOutput, $status, $originalResult);
233
        } else {
234
            $this->writeCommandOutput($output, $structuredOutput);
235
        }
236
        return $status;
237
    }
238
239
    /**
240
     * If the result object is a string, then print it.
241
     */
242
    protected function writeCommandOutput(
243
        OutputInterface $output,
244
        $structuredOutput
245
    ) {
246
        // If there is no formatter, we will print strings,
247
        // but can do no more than that.
248
        if (is_string($structuredOutput)) {
249
            $output->writeln($structuredOutput);
250
        }
251
        return 0;
252
    }
253
254
    /**
255
     * If a status code was set, then return it; otherwise,
256
     * presume success.
257
     */
258
    protected function interpretStatusCode($status)
259
    {
260
        if (isset($status)) {
261
            return $status;
262
        }
263
        return 0;
264
    }
265
}
266