Completed
Pull Request — master (#7)
by
unknown
01:57
created

ShellBuilder::__toArray()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 7
rs 10
cc 3
nc 3
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPSu\ShellCommandBuilder;
6
7
use PHPSu\ShellCommandBuilder\Collection\CollectionTuple;
8
use PHPSu\ShellCommandBuilder\Collection\Pipeline;
9
use PHPSu\ShellCommandBuilder\Collection\Redirection;
10
use PHPSu\ShellCommandBuilder\Collection\ShellList;
11
use PHPSu\ShellCommandBuilder\Definition\ControlOperator;
12
use PHPSu\ShellCommandBuilder\Definition\GroupType;
13
use PHPSu\ShellCommandBuilder\Exception\ShellBuilderException;
14
use TypeError;
15
16
final class ShellBuilder implements ShellInterface
17
{
18
    /** @var array<ShellInterface|CollectionTuple>  */
19
    private $commandList = [];
20
    /** @var int */
21
    private $groupType;
22
    /** @var bool */
23
    private $asynchronously = false;
24
25
    /**
26
     * This is a shortcut for quicker fluid access to the shell builder
27
     * @return static
28
     */
29
    public static function new(): self
30
    {
31
        return new ShellBuilder();
32
    }
33
34
    public function __construct(int $groupType = GroupType::NO_GROUP)
35
    {
36
        $this->groupType = $groupType;
37
    }
38
39
    public function createCommand(string $name, bool $withNewBuilder = false): ShellCommand
40
    {
41
        return new ShellCommand($name, $withNewBuilder ? new self() : $this);
42
    }
43
44
    public function runAsynchronously(bool $isAsync = true): self
45
    {
46
        $this->asynchronously = $isAsync;
47
        return $this;
48
    }
49
50
    /**
51
     * @param string|ShellInterface $command
52
     * @return $this
53
     * @throws ShellBuilderException
54
     */
55
    public function add($command): self
56
    {
57
        $command = $this->parseCommand($command, true);
58
        if (empty($this->commandList)) {
59
            $this->commandList[] = $command;
60
            return $this;
61
        }
62
        $this->commandList[] = ShellList::add($command);
63
        return $this;
64
    }
65
66
    /**
67
     * @param string|ShellInterface $command
68
     * @return $this
69
     * @throws ShellBuilderException
70
     */
71
    public function and($command): self
72
    {
73
        $this->commandList[] = ShellList::addAnd($this->parseCommand($command));
74
        return $this;
75
    }
76
77
    /**
78
     * @param string|ShellInterface $command
79
     * @return $this
80
     * @throws ShellBuilderException
81
     */
82
    public function or($command): self
83
    {
84
        $this->commandList[] = ShellList::addOr($this->parseCommand($command));
85
        return $this;
86
    }
87
88
    /**
89
     * @param string|ShellInterface $command
90
     * @return $this
91
     * @throws ShellBuilderException
92
     */
93
    public function async($command): self
94
    {
95
        $this->commandList[] = ShellList::async($this->parseCommand($command));
96
        return $this;
97
    }
98
99
    /**
100
     * @param string|ShellInterface $command
101
     * @return $this
102
     * @throws ShellBuilderException
103
     */
104
    public function pipe($command): self
105
    {
106
        $this->commandList[] = Pipeline::pipe($this->parseCommand($command));
107
        return $this;
108
    }
109
110
    /**
111
     * @param string|ShellInterface $command
112
     * @return $this
113
     * @throws ShellBuilderException
114
     */
115
    public function pipeWithForward($command): self
116
    {
117
        $this->commandList[] = Pipeline::pipeErrorForward($this->parseCommand($command));
118
        return $this;
119
    }
120
121
    /**
122
     * @param string|ShellInterface $command
123
     * @param bool $append
124
     * @return $this
125
     * @throws ShellBuilderException
126
     */
127
    public function redirectOutput($command, bool $append = false): self
128
    {
129
        $command = $this->parseCommand($command);
130
        $this->commandList[] = Redirection::redirectOutput($command, $append);
131
        return $this;
132
    }
133
134
    /**
135
     * @param string|ShellInterface $command
136
     * @return $this
137
     * @throws ShellBuilderException
138
     */
139
    public function redirectInput($command): self
140
    {
141
        $command = $this->parseCommand($command);
142
        $this->commandList[] = Redirection::redirectInput($command);
143
        return $this;
144
    }
145
146
    /**
147
     * @param string|ShellInterface $command
148
     * @return $this
149
     * @throws ShellBuilderException
150
     */
151
    public function redirectError($command): self
152
    {
153
        $command = $this->parseCommand($command);
154
        $this->commandList[] = Redirection::redirectError($command);
155
        return $this;
156
    }
157
158
    /**
159
     * @param string|ShellInterface $command
160
     * @param bool $toLeft
161
     * @return $this
162
     * @throws ShellBuilderException
163
     */
164
    public function redirect($command, bool $toLeft = true): self
165
    {
166
        $command = $this->parseCommand($command);
167
        $this->commandList[] = Redirection::redirectBetweenFiles($command, $toLeft);
168
        return $this;
169
    }
170
171
    public function redirectErrorToOutput(): self
172
    {
173
        $this->commandList[] = Redirection::redirectErrorToOutput();
174
        return $this;
175
    }
176
177
    public function createGroup(bool $inSameShell = false): self
178
    {
179
        return new self($inSameShell ? GroupType::SAMESHELL_GROUP : GroupType::SUBSHELL_GROUP);
180
    }
181
182
    /**
183
     * @param string|ShellInterface $command
184
     * @param bool $allowEmpty
185
     * @return ShellInterface
186
     * @throws ShellBuilderException
187
     */
188
    private function parseCommand($command, bool $allowEmpty = false): ShellInterface
189
    {
190
        if (is_string($command)) {
191
            $command = $this->createCommand($command);
192
        }
193
        try {
194
            $this->validateCommand($command, $allowEmpty);
195
        } catch (TypeError $typeError) {
196
            throw new ShellBuilderException('Provided the wrong type - only ShellCommand and ShellBuilder allowed');
197
        }
198
        return $command;
199
    }
200
201
    /** @noinspection PhpUnusedParameterInspection */
202
    private function validateCommand(ShellInterface $command, bool $allowEmpty): void
0 ignored issues
show
Unused Code introduced by
The parameter $command is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

202
    private function validateCommand(/** @scrutinizer ignore-unused */ ShellInterface $command, bool $allowEmpty): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
203
    {
204
        if (!$allowEmpty && empty($this->commandList)) {
205
            throw new ShellBuilderException('You have to first add a command before you can combine it');
206
        }
207
    }
208
209
    /**
210
     * @return array<mixed>
211
     */
212
    public function __toArray(): array
213
    {
214
        $commands = [];
215
        foreach ($this->commandList as $item) {
216
            $commands[] = $item instanceof ShellInterface ? $item->__toArray() : $item;
217
        }
218
        return $commands;
219
    }
220
221
    public function __toString(): string
222
    {
223
        $result = '';
224
        if ($this->asynchronously) {
225
            $result = 'coproc ';
226
        }
227
        foreach ($this->commandList as $command) {
228
            $result .= $command;
229
        }
230
        if ($this->groupType === GroupType::SAMESHELL_GROUP) {
231
            return sprintf(
232
                '%s%s;%s',
233
                ControlOperator::CURLY_BLOCK_DEFINITON_OPEN,
234
                $result,
235
                ControlOperator::CURLY_BLOCK_DEFINITON_CLOSE
236
            );
237
        }
238
        if ($this->groupType === GroupType::SUBSHELL_GROUP) {
239
            return sprintf(
240
                '%s%s%s',
241
                ControlOperator::BLOCK_DEFINITON_OPEN,
242
                $result,
243
                ControlOperator::BLOCK_DEFINITON_CLOSE
244
            );
245
        }
246
        return $result;
247
    }
248
}
249