4 use Robo\Contract\TaskInterface;
5 use Robo\Exception\TaskExitException;
8 class Result extends ResultData
13 public static $stopOnFail = false;
16 * @var \Robo\Contract\TaskInterface
21 * @param \Robo\Contract\TaskInterface $task
22 * @param string $exitCode
23 * @param string $message
26 public function __construct(TaskInterface $task, $exitCode, $message = '', $data = [])
28 parent::__construct($exitCode, $message, $data);
32 if (self::$stopOnFail) {
38 * Tasks should always return a Result. However, they are also
39 * allowed to return NULL or an array to indicate success.
41 public static function ensureResult($task, $result)
43 if ($result instanceof Result) {
46 if (!isset($result)) {
47 return static::success($task);
49 if ($result instanceof Data) {
50 return static::success($task, $result->getMessage(), $result->getData());
52 if ($result instanceof ResultData) {
53 return new Result($task, $result->getExitCode(), $result->getMessage(), $result->getData());
55 if (is_array($result)) {
56 return static::success($task, '', $result);
58 throw new \Exception(sprintf('Task %s returned a %s instead of a \Robo\Result.', get_class($task), get_class($result)));
61 protected function printResult()
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();
71 if ($resultPrinter->printResult($this)) {
72 $this->alreadyPrinted();
78 * @param \Robo\Contract\TaskInterface $task
79 * @param string $extension
80 * @param string $service
82 * @return \Robo\Result
84 public static function errorMissingExtension(TaskInterface $task, $extension, $service)
86 $messageTpl = 'PHP extension required for %s. Please enable %s';
87 $message = sprintf($messageTpl, $service, $extension);
89 return self::error($task, $message);
93 * @param \Robo\Contract\TaskInterface $task
94 * @param string $class
95 * @param string $package
97 * @return \Robo\Result
99 public static function errorMissingPackage(TaskInterface $task, $class, $package)
101 $messageTpl = 'Class %s not found. Please install %s Composer package';
102 $message = sprintf($messageTpl, $class, $package);
104 return self::error($task, $message);
108 * @param \Robo\Contract\TaskInterface $task
109 * @param string $message
112 * @return \Robo\Result
114 public static function error(TaskInterface $task, $message, $data = [])
116 return new self($task, self::EXITCODE_ERROR, $message, $data);
120 * @param \Robo\Contract\TaskInterface $task
121 * @param \Exception $e
124 * @return \Robo\Result
126 public static function fromException(TaskInterface $task, \Exception $e, $data = [])
128 $exitCode = $e->getCode();
130 $exitCode = self::EXITCODE_ERROR;
132 return new self($task, $exitCode, $e->getMessage(), $data);
136 * @param \Robo\Contract\TaskInterface $task
137 * @param string $message
140 * @return \Robo\Result
142 public static function success(TaskInterface $task, $message = '', $data = [])
144 return new self($task, self::EXITCODE_OK, $message, $data);
148 * Return a context useful for logging messages.
152 public function getContext()
154 $task = $this->getTask();
156 return TaskInfo::getTaskContext($task) + [
157 'code' => $this->getExitCode(),
158 'data' => $this->getArrayCopy(),
159 'time' => $this->getExecutionTime(),
160 'message' => $this->getMessage(),
165 * Add the results from the most recent task to the accumulated
166 * results from all tasks that have run so far, merging data
169 * @param int|string $key
170 * @param \Robo\Result $taskResult
172 public function accumulate($key, Result $taskResult)
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);
186 $this[$key] = $taskResult;
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.
195 * @param int|string $key
199 public static function isUnnamed($key)
201 return is_numeric($key);
205 * @return \Robo\Contract\TaskInterface
207 public function getTask()
213 * @return \Robo\Contract\TaskInterface
215 public function cloneTask()
217 $reflect = new \ReflectionClass(get_class($this->task));
218 return $reflect->newInstanceArgs(func_get_args());
224 * @deprecated since 1.0.
226 * @see wasSuccessful()
228 public function __invoke()
230 trigger_error(__METHOD__ . ' is deprecated: use wasSuccessful() instead.', E_USER_DEPRECATED);
231 return $this->wasSuccessful();
237 public function stopOnFail()
239 if (!$this->wasSuccessful()) {
240 $resultPrinter = Robo::resultPrinter();
241 if ($resultPrinter) {
242 $resultPrinter->printStopOnFail($this);
244 $this->exitEarly($this->getExitCode());
252 * @throws \Robo\Exception\TaskExitException
254 private function exitEarly($status)
256 throw new TaskExitException($this->getTask(), $this->getMessage(), $status);