Completed
Push — master ( 3164b9...6629c2 )
by Greg
02:30
created

IO::stderr()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
namespace Robo\Common;
3
4
use Robo\Symfony\IOStorage;
5
use Symfony\Component\Console\Helper\QuestionHelper;
6
use Symfony\Component\Console\Input\InputInterface;
7
use Symfony\Component\Console\Output\ConsoleOutputInterface;
8
use Symfony\Component\Console\Output\OutputInterface;
9
use Symfony\Component\Console\Question\ConfirmationQuestion;
10
use Symfony\Component\Console\Question\Question;
11
use Symfony\Component\Console\Style\SymfonyStyle;
12
13
trait IO
14
{
15
    use InputAwareTrait {
16
        input as parentInput;
17
    }
18
    use OutputAwareTrait {
19
        output as parentOutput;
20
    }
21
22
    /**
23
     * @var Robo\Symfony\IOStorage
24
     */
25
    protected $ioStorage;
26
27
    public function setIOStorage(IOStorage $ioStorage)
28
    {
29
        $this->ioStorage = $ioStorage;
0 ignored issues
show
Documentation Bug introduced by Greg Anderson
It seems like $ioStorage of type object<Robo\Symfony\IOStorage> is incompatible with the declared type object<Robo\Common\Robo\Symfony\IOStorage> of property $ioStorage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
30
    }
31
32
    public function resetIO(InputInterface $input, OutputInterface $output)
33
    {
34
        if (!$this->ioStorage) {
35
            $this->ioStorage = new IOStorage();
0 ignored issues
show
Documentation Bug introduced by Greg Anderson
It seems like new \Robo\Symfony\IOStorage() of type object<Robo\Symfony\IOStorage> is incompatible with the declared type object<Robo\Common\Robo\Symfony\IOStorage> of property $ioStorage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
36
        }
37
        $this->ioStorage->create($input, $output);
38
    }
39
40
    protected function output()
41
    {
42
        $result = null;
43
        if ($this->ioStorage) {
44
            $result = $this->ioStorage->output();
45
        }
46
        return $result ?: $this->parentOutput();
0 ignored issues
show
Bug introduced by Greg Anderson
The method parentOutput() does not exist on Robo\Common\IO. Did you maybe mean output()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
47
    }
48
49
    protected function stderr()
50
    {
51
        $output = $this->output();
52
        if ($output instanceof ConsoleOutputInterface) {
53
            $output = $output->getErrorOutput();
54
        }
55
        return $output;
56
    }
57
58
    protected function input()
59
    {
60
        $result = null;
61
        if ($this->ioStorage) {
62
            $result = $this->ioStorage->input();
63
        }
64
        return $result ?: $this->parentInput();
0 ignored issues
show
Bug introduced by Greg Anderson
It seems like parentInput() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
65
    }
66
67
    /**
68
     * Provide access to SymfonyStyle object.
69
     *
70
     * @return SymfonyStyle
71
     *
72
     * @see http://symfony.com/blog/new-in-symfony-2-8-console-style-guide
73
     */
74
    protected function io()
75
    {
76
        if (!$this->ioStorage) {
77
            $this->ioStorage = new IOStorage();
0 ignored issues
show
Documentation Bug introduced by Greg Anderson
It seems like new \Robo\Symfony\IOStorage() of type object<Robo\Symfony\IOStorage> is incompatible with the declared type object<Robo\Common\Robo\Symfony\IOStorage> of property $ioStorage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78
        }
79
        return $this->ioStorage->get($this->input, $this->output);
80
    }
81
82
    /**
83
     * @param string $nonDecorated
84
     * @param string $decorated
85
     *
86
     * @return string
87
     */
88
    protected function decorationCharacter($nonDecorated, $decorated)
89
    {
90
        if (!$this->output()->isDecorated() || (strncasecmp(PHP_OS, 'WIN', 3) == 0)) {
91
            return $nonDecorated;
92
        }
93
        return $decorated;
94
    }
95
96
    /**
97
     * @param string $text
98
     */
99
    protected function say($text)
100
    {
101
        $char = $this->decorationCharacter('>', '➜');
102
        $this->writeln("$char  $text");
103
    }
104
105
    /**
106
     * @param string $text
107
     * @param int $length
108
     * @param string $color
109
     */
110
    protected function yell($text, $length = 40, $color = 'green')
111
    {
112
        $char = $this->decorationCharacter(' ', '➜');
113
        $format = "$char  <fg=white;bg=$color;options=bold>%s</fg=white;bg=$color;options=bold>";
114
        $this->formattedOutput($text, $length, $format);
115
    }
116
117
    /**
118
     * @param string $text
119
     * @param int $length
120
     * @param string $format
121
     */
122
    protected function formattedOutput($text, $length, $format)
123
    {
124
        $lines = explode("\n", trim($text, "\n"));
125
        $maxLineLength = array_reduce(array_map('strlen', $lines), 'max');
126
        $length = max($length, $maxLineLength);
127
        $len = $length + 2;
128
        $space = str_repeat(' ', $len);
129
        $this->writeln(sprintf($format, $space));
130
        foreach ($lines as $line) {
131
            $line = str_pad($line, $length, ' ', STR_PAD_BOTH);
132
            $this->writeln(sprintf($format, " $line "));
133
        }
134
        $this->writeln(sprintf($format, $space));
135
    }
136
137
    /**
138
     * @param string $question
139
     * @param bool $hideAnswer
140
     *
141
     * @return string
142
     */
143
    protected function ask($question, $hideAnswer = false)
144
    {
145
        if ($hideAnswer) {
146
            return $this->askHidden($question);
147
        }
148
        return $this->doAsk(new Question($this->formatQuestion($question)));
149
    }
150
151
    /**
152
     * @param string $question
153
     *
154
     * @return string
155
     */
156
    protected function askHidden($question)
157
    {
158
        $question = new Question($this->formatQuestion($question));
159
        $question->setHidden(true);
160
        return $this->doAsk($question);
161
    }
162
163
    /**
164
     * @param string $question
165
     * @param string $default
166
     *
167
     * @return string
168
     */
169
    protected function askDefault($question, $default)
170
    {
171
        return $this->doAsk(new Question($this->formatQuestion("$question [$default]"), $default));
172
    }
173
174
    /**
175
     * @param string $question
176
     *
177
     * @return string
178
     */
179
    protected function confirm($question)
180
    {
181
        return $this->doAsk(new ConfirmationQuestion($this->formatQuestion($question . ' (y/n)'), false));
182
    }
183
184
    /**
185
     * @param \Symfony\Component\Console\Question\Question $question
186
     *
187
     * @return string
188
     */
189
    protected function doAsk(Question $question)
190
    {
191
        return $this->getDialog()->ask($this->input(), $this->output(), $question);
192
    }
193
194
    /**
195
     * @param string $message
196
     *
197
     * @return string
198
     */
199
    protected function formatQuestion($message)
200
    {
201
        return  "<question>?  $message</question> ";
202
    }
203
204
    /**
205
     * @return \Symfony\Component\Console\Helper\QuestionHelper
206
     */
207
    protected function getDialog()
208
    {
209
        return new QuestionHelper();
210
    }
211
212
    /**
213
     * @param $text
214
     */
215
    protected function writeln($text)
216
    {
217
        $this->output()->writeln($text);
218
    }
219
}
220