Completed
Push — master ( 8b8afe...5f2bbe )
by Greg
02:21
created

src/Result.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Robo;
3
4
use Robo\Contract\TaskInterface;
5
use Robo\Exception\TaskExitException;
6
use Robo\State\Data;
7
8
class Result extends ResultData
9
{
10
    /**
11
     * @var bool
12
     */
13
    public static $stopOnFail = false;
14
15
    /**
16
     * @var \Robo\Contract\TaskInterface
17
     */
18
    protected $task;
19
20
    /**
21
     * @param \Robo\Contract\TaskInterface $task
22
     * @param string $exitCode
23
     * @param string $message
24
     * @param array $data
25
     */
26
    public function __construct(TaskInterface $task, $exitCode, $message = '', $data = [])
27
    {
28
        parent::__construct($exitCode, $message, $data);
29
        $this->task = $task;
30
        $this->printResult();
31
32
        if (self::$stopOnFail) {
33
            $this->stopOnFail();
34
        }
35
    }
36
37
    /**
38
     * Tasks should always return a Result. However, they are also
39
     * allowed to return NULL or an array to indicate success.
40
     */
41
    public static function ensureResult($task, $result)
42
    {
43
        if ($result instanceof Result) {
44
            return $result;
45
        }
46
        if (!isset($result)) {
47
            return static::success($task);
48
        }
49
        if ($result instanceof Data) {
50
            return static::success($task, $result->getMessage(), $result->getData());
51
        }
52
        if ($result instanceof ResultData) {
53
            return new Result($task, $result->getExitCode(), $result->getMessage(), $result->getData());
54
        }
55
        if (is_array($result)) {
56
            return static::success($task, '', $result);
57
        }
58
        throw new \Exception(sprintf('Task %s returned a %s instead of a \Robo\Result.', get_class($task), get_class($result)));
59
    }
60
61
    protected function printResult()
62
    {
63
        // For historic reasons, the Result constructor is responsible
64
        // for printing task results.
65
        // TODO: Make IO the responsibility of some other class. Maintaining
66
        // existing behavior for backwards compatibility. This is undesirable
67
        // in the long run, though, as it can result in unwanted repeated input
68
        // in task collections et. al.
69
        $resultPrinter = Robo::resultPrinter();
70
        if ($resultPrinter) {
71
            if ($resultPrinter->printResult($this)) {
72
                $this->alreadyPrinted();
0 ignored issues
show
The call to the method Robo\Result::alreadyPrinted() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
73
            }
74
        }
75
    }
76
77
    /**
78
     * @param \Robo\Contract\TaskInterface $task
79
     * @param string $extension
80
     * @param string $service
81
     *
82
     * @return \Robo\Result
83
     */
84
    public static function errorMissingExtension(TaskInterface $task, $extension, $service)
85
    {
86
        $messageTpl = 'PHP extension required for %s. Please enable %s';
87
        $message = sprintf($messageTpl, $service, $extension);
88
89
        return self::error($task, $message);
90
    }
91
92
    /**
93
     * @param \Robo\Contract\TaskInterface $task
94
     * @param string $class
95
     * @param string $package
96
     *
97
     * @return \Robo\Result
98
     */
99
    public static function errorMissingPackage(TaskInterface $task, $class, $package)
100
    {
101
        $messageTpl = 'Class %s not found. Please install %s Composer package';
102
        $message = sprintf($messageTpl, $class, $package);
103
104
        return self::error($task, $message);
105
    }
106
107
    /**
108
     * @param \Robo\Contract\TaskInterface $task
109
     * @param string $message
110
     * @param array $data
111
     *
112
     * @return \Robo\Result
113
     */
114
    public static function error(TaskInterface $task, $message, $data = [])
115
    {
116
        return new self($task, self::EXITCODE_ERROR, $message, $data);
117
    }
118
119
    /**
120
     * @param \Robo\Contract\TaskInterface $task
121
     * @param \Exception $e
122
     * @param array $data
123
     *
124
     * @return \Robo\Result
125
     */
126
    public static function fromException(TaskInterface $task, \Exception $e, $data = [])
127
    {
128
        $exitCode = $e->getCode();
129
        if (!$exitCode) {
130
            $exitCode = self::EXITCODE_ERROR;
131
        }
132
        return new self($task, $exitCode, $e->getMessage(), $data);
133
    }
134
135
    /**
136
     * @param \Robo\Contract\TaskInterface $task
137
     * @param string $message
138
     * @param array $data
139
     *
140
     * @return \Robo\Result
141
     */
142
    public static function success(TaskInterface $task, $message = '', $data = [])
143
    {
144
        return new self($task, self::EXITCODE_OK, $message, $data);
145
    }
146
147
    /**
148
     * Return a context useful for logging messages.
149
     *
150
     * @return array
151
     */
152
    public function getContext()
153
    {
154
        $task = $this->getTask();
155
156
        return TaskInfo::getTaskContext($task) + [
157
            'code' => $this->getExitCode(),
158
            'data' => $this->getArrayCopy(),
159
            'time' => $this->getExecutionTime(),
160
            'message' => $this->getMessage(),
161
        ];
162
    }
163
164
    /**
165
     * Add the results from the most recent task to the accumulated
166
     * results from all tasks that have run so far, merging data
167
     * as necessary.
168
     *
169
     * @param int|string $key
170
     * @param \Robo\Result $taskResult
171
     */
172
    public function accumulate($key, Result $taskResult)
173
    {
174
        // If the task is unnamed, then all of its data elements
175
        // just get merged in at the top-level of the final Result object.
176
        if (static::isUnnamed($key)) {
177
            $this->merge($taskResult);
178
        } elseif (isset($this[$key])) {
179
            // There can only be one task with a given name; however, if
180
            // there are tasks added 'before' or 'after' the named task,
181
            // then the results from these will be stored under the same
182
            // name unless they are given a name of their own when added.
183
            $current = $this[$key];
184
            $this[$key] = $taskResult->merge($current);
185
        } else {
186
            $this[$key] = $taskResult;
187
        }
188
    }
189
190
    /**
191
     * We assume that named values (e.g. for associative array keys)
192
     * are non-numeric; numeric keys are presumed to simply be the
193
     * index of an array, and therefore insignificant.
194
     *
195
     * @param int|string $key
196
     *
197
     * @return bool
198
     */
199
    public static function isUnnamed($key)
200
    {
201
        return is_numeric($key);
202
    }
203
204
    /**
205
     * @return \Robo\Contract\TaskInterface
206
     */
207
    public function getTask()
208
    {
209
        return $this->task;
210
    }
211
212
    /**
213
     * @return \Robo\Contract\TaskInterface
214
     */
215
    public function cloneTask()
216
    {
217
        $reflect  = new \ReflectionClass(get_class($this->task));
218
        return $reflect->newInstanceArgs(func_get_args());
219
    }
220
221
    /**
222
     * @return bool
223
     *
224
     * @deprecated since 1.0.
225
     *
226
     * @see wasSuccessful()
227
     */
228
    public function __invoke()
229
    {
230
        trigger_error(__METHOD__ . ' is deprecated: use wasSuccessful() instead.', E_USER_DEPRECATED);
231
        return $this->wasSuccessful();
232
    }
233
234
    /**
235
     * @return $this
236
     */
237
    public function stopOnFail()
238
    {
239
        if (!$this->wasSuccessful()) {
240
            $resultPrinter = Robo::resultPrinter();
241
            if ($resultPrinter) {
242
                $resultPrinter->printStopOnFail($this);
243
            }
244
            $this->exitEarly($this->getExitCode());
245
        }
246
        return $this;
247
    }
248
249
    /**
250
     * @param int $status
251
     *
252
     * @throws \Robo\Exception\TaskExitException
253
     */
254
    private function exitEarly($status)
255
    {
256
        throw new TaskExitException($this->getTask(), $this->getMessage(), $status);
257
    }
258
}
259