Completed
Pull Request — master (#179)
by Greg
01:46
created

ResultWriter::writeUsingFormatter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
namespace Consolidation\AnnotatedCommand;
3
4
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ReplaceCommandHookDispatcher;
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
use Consolidation\AnnotatedCommand\Options\PrepareFormatter;
13
14
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\InitializeHookDispatcher;
15
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\OptionsHookDispatcher;
16
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\InteractHookDispatcher;
17
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ValidateHookDispatcher;
18
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ProcessResultHookDispatcher;
19
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\StatusDeterminerHookDispatcher;
20
use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ExtracterHookDispatcher;
21
22
/**
23
 * Write the results of a command. Inject your ResultWriter
24
 * into the CommandProcessor.
25
 */
26
class ResultWriter
27
{
28
    /** var FormatterManager */
29
    protected $formatterManager;
30
    /** @var callable */
31
    protected $displayErrorFunction;
32
33
    public function setFormatterManager(FormatterManager $formatterManager)
34
    {
35
        $this->formatterManager = $formatterManager;
36
        return $this;
37
    }
38
39
    /**
40
     * Return the formatter manager
41
     * @return FormatterManager
42
     */
43
    public function formatterManager()
44
    {
45
        return $this->formatterManager;
46
    }
47
48
    public function setDisplayErrorFunction(callable $fn)
49
    {
50
        $this->displayErrorFunction = $fn;
51
        return $this;
52
    }
53
54
    /**
55
     * Handle the result output and status code calculation.
56
     */
57
    public function handle(OutputInterface $output, $result, CommandData $commandData, $statusCodeDispatcher = null, $extractDispatcher = null)
58
    {
59
        // A little messy, for backwards compatibility: if the result implements
60
        // ExitCodeInterface, then use that as the exit code. If a status code
61
        // dispatcher returns a non-zero result, then we will never print a
62
        // result.
63
        if ($result instanceof ExitCodeInterface) {
64
            $status = $result->getExitCode();
65
        } elseif (isset($statusCodeDispatcher)) {
66
            $status = $statusCodeDispatcher->determineStatusCode($result);
67
            if (isset($status) && ($status != 0)) {
68
                return $status;
69
            }
70
        }
71
        // If the result is an integer and no separate status code was provided, then use the result as the status and do no output.
72
        if (is_integer($result) && !isset($status)) {
73
            return $result;
74
        }
75
        $status = $this->interpretStatusCode($status);
0 ignored issues
show
Bug introduced by
The variable $status does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
76
77
        // Get the structured output, the output stream and the formatter
78
        $structuredOutput = $result;
79
        if (isset($extractDispatcher)) {
80
            $structuredOutput = $extractDispatcher->extractOutput($result);
81
        }
82
        if (($status != 0) && is_string($structuredOutput)) {
83
            $output = $this->chooseOutputStream($output, $status);
84
            return $this->writeErrorMessage($output, $status, $structuredOutput, $result);
85
        }
86
        if ($this->dataCanBeFormatted($structuredOutput) && isset($this->formatterManager)) {
87
            return $this->writeUsingFormatter($output, $structuredOutput, $commandData, $status);
88
        }
89
        return $this->writeCommandOutput($output, $structuredOutput, $status);
90
    }
91
92
    protected function dataCanBeFormatted($structuredOutput)
93
    {
94
        if (!isset($this->formatterManager)) {
95
            return false;
96
        }
97
        return
98
            is_object($structuredOutput) ||
99
            is_array($structuredOutput);
100
    }
101
102
    /**
103
     * Determine the formatter that should be used to render
104
     * output.
105
     *
106
     * If the user specified a format via the --format option,
107
     * then always return that.  Otherwise, return the default
108
     * format, unless --pipe was specified, in which case
109
     * return the default pipe format, format-pipe.
110
     *
111
     * n.b. --pipe is a handy option introduced in Drush 2
112
     * (or perhaps even Drush 1) that indicates that the command
113
     * should select the output format that is most appropriate
114
     * for use in scripts (e.g. to pipe to another command).
115
     *
116
     * @return string
117
     */
118
    protected function getFormat(FormatterOptions $options)
119
    {
120
        // In Symfony Console, there is no way for us to differentiate
121
        // between the user specifying '--format=table', and the user
122
        // not specifying --format when the default value is 'table'.
123
        // Therefore, we must make --field always override --format; it
124
        // cannot become the default value for --format.
125
        if ($options->get('field')) {
126
            return 'string';
127
        }
128
        $defaults = [];
129
        if ($options->get('pipe')) {
130
            return $options->get('pipe-format', [], 'tsv');
131
        }
132
        return $options->getFormat($defaults);
133
    }
134
135
    /**
136
     * Determine whether we should use stdout or stderr.
137
     */
138
    protected function chooseOutputStream(OutputInterface $output, $status)
139
    {
140
        // If the status code indicates an error, then print the
141
        // result to stderr rather than stdout
142
        if ($status && ($output instanceof ConsoleOutputInterface)) {
143
            return $output->getErrorOutput();
144
        }
145
        return $output;
146
    }
147
148
    /**
149
     * Call the formatter to output the provided data.
150
     */
151
    protected function writeUsingFormatter(OutputInterface $output, $structuredOutput, CommandData $commandData, $status = 0)
152
    {
153
        $formatterOptions = $commandData->formatterOptions();
154
        $format = $this->getFormat($formatterOptions);
155
        $this->formatterManager->write(
156
            $output,
157
            $format,
158
            $structuredOutput,
159
            $formatterOptions
160
        );
161
        return $status;
162
    }
163
164
    /**
165
     * Description
166
     * @param OutputInterface $output
167
     * @param int $status
168
     * @param string $structuredOutput
169
     * @param mixed $originalResult
170
     * @return type
171
     */
172
    protected function writeErrorMessage($output, $status, $structuredOutput, $originalResult)
173
    {
174
        if (isset($this->displayErrorFunction)) {
175
            call_user_func($this->displayErrorFunction, $output, $structuredOutput, $status, $originalResult);
176
        } else {
177
            $this->writeCommandOutput($output, $structuredOutput);
178
        }
179
        return $status;
180
    }
181
182
    /**
183
     * If the result object is a string, then print it.
184
     */
185
    protected function writeCommandOutput(
186
        OutputInterface $output,
187
        $structuredOutput,
188
        $status = 0
189
    ) {
190
        // If there is no formatter, we will print strings,
191
        // but can do no more than that.
192
        if (is_string($structuredOutput)) {
193
            $output->writeln($structuredOutput);
194
        }
195
        return $status;
196
    }
197
198
    /**
199
     * If a status code was set, then return it; otherwise,
200
     * presume success.
201
     */
202
    protected function interpretStatusCode($status)
203
    {
204
        if (isset($status)) {
205
            return $status;
206
        }
207
        return 0;
208
    }
209
}
210