Completed
Push — master ( e1c388...7bf58d )
by
unknown
12:55 queued 10:58
created

ShellCommand::addShortOption()   A

Complexity

Conditions 3
Paths 2

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 2
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPSu\ShellCommandBuilder;
6
7
use PHPSu\ShellCommandBuilder\Exception\ShellBuilderException;
8
use PHPSu\ShellCommandBuilder\Literal\ShellArgument;
9
use PHPSu\ShellCommandBuilder\Literal\ShellEnvironmentVariable;
10
use PHPSu\ShellCommandBuilder\Literal\ShellExecutable;
11
use PHPSu\ShellCommandBuilder\Literal\ShellOption;
12
use PHPSu\ShellCommandBuilder\Literal\ShellShortOption;
13
use PHPSu\ShellCommandBuilder\Literal\ShellWord;
14
15
final class ShellCommand implements ShellInterface
16
{
17
    /**
18
     * @var ShellWord
19
     * @psalm-readonly
20
     */
21
    private $executable;
22
    /** @var array<ShellWord> */
23
    private $arguments = [];
24
    /** @var array<ShellWord> */
25
    private $environmentVariables = [];
26
    /** @var bool  */
27
    private $isCommandSubstitution = false;
28
    /** @var ShellBuilder|null */
29
    private $parentBuilder;
30
    /** @var bool */
31
    private $invertOutput = false;
32
33
    public function __construct(string $name, ShellBuilder $builder = null)
34
    {
35
        $this->executable = new ShellExecutable($name);
36
        $this->parentBuilder = $builder;
37
    }
38
39
    public function addToBuilder(): ShellBuilder
40
    {
41
        if ($this->parentBuilder === null) {
42
            throw new ShellBuilderException('You need to create a ShellBuilder first before you can use it within a command');
43
        }
44
        return $this->parentBuilder->add($this);
45
    }
46
47
    public function toggleCommandSubstitution(): self
48
    {
49
        $this->isCommandSubstitution = !$this->isCommandSubstitution;
50
        return $this;
51
    }
52
53
    public function invert(bool $invert = true): self
54
    {
55
        $this->invertOutput = $invert;
56
        return $this;
57
    }
58
59
    /**
60
     * @param string $option
61
     * @param ShellInterface|string|mixed $value
62
     * @param bool $escapeArgument
63
     * @param bool $withAssignOperator
64
     * @return self
65
     * @throws ShellBuilderException
66
     */
67
    public function addShortOption(string $option, $value = '', bool $escapeArgument = true, bool $withAssignOperator = false): self
68
    {
69
        if (!($value instanceof ShellInterface || is_string($value))) {
70
            throw new ShellBuilderException('Provided the wrong type - only ShellCommand and ShellBuilder allowed');
71
        }
72
        $word = new ShellShortOption($option, $value);
73
        return $this->add($word, $escapeArgument, $withAssignOperator);
74
    }
75
76
    /**
77
     * @param string $option
78
     * @param ShellInterface|string|mixed $value
79
     * @param bool $escapeArgument
80
     * @param bool $withAssignOperator
81
     * @return self
82
     * @throws ShellBuilderException
83
     */
84
    public function addOption(string $option, $value = '', bool $escapeArgument = true, bool $withAssignOperator = false): self
85
    {
86
        if (!($value instanceof ShellInterface || is_string($value))) {
87
            throw new ShellBuilderException('Provided the wrong type - only ShellCommand and ShellBuilder allowed');
88
        }
89
        $word = new ShellOption($option, $value);
90
        return $this->add($word, $escapeArgument, $withAssignOperator);
91
    }
92
93
    /**
94
     * @param ShellInterface|string|mixed $argument
95
     * @param bool $escapeArgument
96
     * @return self
97
     * @throws ShellBuilderException
98
     */
99
    public function addArgument($argument, bool $escapeArgument = true): self
100
    {
101
        if (!($argument instanceof ShellInterface || is_string($argument))) {
102
            throw new ShellBuilderException('Provided the wrong type - only ShellCommand and ShellBuilder allowed');
103
        }
104
        $word = new ShellArgument($argument);
105
        return $this->add($word, $escapeArgument);
106
    }
107
108
    /**
109
     * This is an alias for argument, that automatically escapes the argument.
110
     * It does in the end does not provide any additional functionality
111
     *
112
     * @param ShellInterface $argument
113
     * @return $this
114
     * @throws ShellBuilderException
115
     */
116
    public function addSubCommand(ShellInterface $argument): self
117
    {
118
        return $this->addArgument($argument, true);
119
    }
120
121
    /**
122
     * @param ShellInterface|string|mixed $argument
123
     * @return self
124
     * @throws ShellBuilderException
125
     */
126
    public function addNoSpaceArgument($argument): self
127
    {
128
        if (!($argument instanceof ShellInterface || is_string($argument))) {
129
            throw new ShellBuilderException('Provided the wrong type - only ShellCommand and ShellBuilder allowed');
130
        }
131
        $word = new ShellArgument($argument);
132
        $word->setSpaceAfterValue(false);
133
        return $this->add($word, false);
134
    }
135
136
    private function add(ShellWord $word, bool $escapeArgument, bool $withAssignOperator = false): self
137
    {
138
        $word->setEscape($escapeArgument);
139
        $word->setAssignOperator($withAssignOperator);
140
        $this->arguments[] = $word;
141
        return $this;
142
    }
143
144
    public function addEnv(string $name, string $value): self
145
    {
146
        $word = new ShellEnvironmentVariable($name, $value);
147
        $this->environmentVariables[$name] = $word;
148
        return $this;
149
    }
150
151
    private function argumentsToString(): string
152
    {
153
        $result = [];
154
        foreach ($this->arguments as $part) {
155
            $result[] = $part;
156
        }
157
        return trim(implode('', $result));
158
    }
159
160
    private function environmentVariablesToString(): string
161
    {
162
        $result = [];
163
        foreach ($this->environmentVariables as $part) {
164
            $result[] = $part;
165
        }
166
        return implode('', $result);
167
    }
168
169
    /**
170
     * @return array<string, mixed>
171
     */
172
    public function __toArray(): array
173
    {
174
        $commands = [];
175
        foreach ($this->arguments as $item) {
176
            $commands[] = $item->__toArray();
177
        }
178
        $envs = [];
179
        foreach ($this->environmentVariables as $item) {
180
            $envs[] = $item->__toArray();
181
        }
182
        return [
183
            'executable' => $this->executable,
184
            'arguments' => $commands,
185
            'isCommandSubstitution' => $this->isCommandSubstitution,
186
            'environmentVariables' => $envs,
187
        ];
188
    }
189
190
    public function __toString(): string
191
    {
192
        /** @psalm-suppress ImplicitToStringCast */
193
        $result = (sprintf(
194
            '%s%s%s%s',
195
            $this->invertOutput ? '! ' : '',
196
            empty($this->environmentVariables) ? '' : $this->environmentVariablesToString(),
197
            $this->executable,
198
            empty($this->arguments) ? '' : ' ' . $this->argumentsToString()
199
        ));
200
        if ($this->isCommandSubstitution) {
201
            return sprintf("\$(%s)", $result);
202
        }
203
        return $result;
204
    }
205
}
206