Completed
Push — master ( 930cbb...47d5e6 )
by Greg
02:29
created

CommandProcessor::hookManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 0
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\Options\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 ($this->dataCanBeFormatted($structuredOutput)) {
139
            return $this->writeUsingFormatter($output, $structuredOutput, $annotationData, $options);
140
        }
141
        return $this->writeCommandOutput($output, $structuredOutput);
142
    }
143
144
    protected function dataCanBeFormatted($structuredOutput)
145
    {
146
        if (!isset($this->formatterManager)) {
147
            return false;
148
        }
149
        return
150
            is_object($structuredOutput) ||
151
            is_array($structuredOutput);
152
    }
153
154
    /**
155
     * Run the main command callback
156
     */
157
    protected function runCommandCallback($commandCallback, $args)
158
    {
159
        $result = false;
160
        try {
161
            $result = call_user_func_array($commandCallback, $args);
162
        } catch (\Exception $e) {
163
            $result = new CommandError($e->getMessage(), $e->getCode());
164
        }
165
        return $result;
166
    }
167
168
    /**
169
     * Determine the formatter that should be used to render
170
     * output.
171
     *
172
     * If the user specified a format via the --format option,
173
     * then always return that.  Otherwise, return the default
174
     * format, unless --pipe was specified, in which case
175
     * return the default pipe format, format-pipe.
176
     *
177
     * n.b. --pipe is a handy option introduced in Drush 2
178
     * (or perhaps even Drush 1) that indicates that the command
179
     * should select the output format that is most appropriate
180
     * for use in scripts (e.g. to pipe to another command).
181
     *
182
     * @return string
183
     */
184
    protected function getFormat($options)
185
    {
186
        $options += [
187
            'default-format' => false,
188
            'pipe' => false,
189
        ];
190
        $options += [
191
            'format' => $options['default-format'],
192
            'format-pipe' => $options['default-format'],
193
        ];
194
195
        $format = $options['format'];
196
        if ($options['pipe']) {
197
            $format = $options['format-pipe'];
198
        }
199
        return $format;
200
    }
201
202
    /**
203
     * Determine whether we should use stdout or stderr.
204
     */
205
    protected function chooseOutputStream(OutputInterface $output, $status)
206
    {
207
        // If the status code indicates an error, then print the
208
        // result to stderr rather than stdout
209
        if ($status && ($output instanceof ConsoleOutputInterface)) {
210
            return $output->getErrorOutput();
211
        }
212
        return $output;
213
    }
214
215
    /**
216
     * Call the formatter to output the provided data.
217
     */
218
    protected function writeUsingFormatter(OutputInterface $output, $structuredOutput, AnnotationData $annotationData, $options)
219
    {
220
        $format = $this->getFormat($options);
221
        $formatterOptions = new FormatterOptions($annotationData->getArrayCopy(), $options);
222
        $this->formatterManager->write(
223
            $output,
224
            $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...
225
            $structuredOutput,
226
            $formatterOptions
227
        );
228
        return 0;
229
    }
230
231
    /**
232
     * Description
233
     * @param OutputInterface $output
234
     * @param int $status
235
     * @param string $structuredOutput
236
     * @param mixed $originalResult
237
     * @return type
238
     */
239
    protected function writeErrorMessage($output, $status, $structuredOutput, $originalResult)
240
    {
241
        if (isset($this->displayErrorFunction)) {
242
            call_user_func($this->displayErrorFunction, $output, $structuredOutput, $status, $originalResult);
243
        } else {
244
            $this->writeCommandOutput($output, $structuredOutput);
245
        }
246
        return $status;
247
    }
248
249
    /**
250
     * If the result object is a string, then print it.
251
     */
252
    protected function writeCommandOutput(
253
        OutputInterface $output,
254
        $structuredOutput
255
    ) {
256
        // If there is no formatter, we will print strings,
257
        // but can do no more than that.
258
        if (is_string($structuredOutput)) {
259
            $output->writeln($structuredOutput);
260
        }
261
        return 0;
262
    }
263
264
    /**
265
     * If a status code was set, then return it; otherwise,
266
     * presume success.
267
     */
268
    protected function interpretStatusCode($status)
269
    {
270
        if (isset($status)) {
271
            return $status;
272
        }
273
        return 0;
274
    }
275
}
276