Passed
Pull Request — master (#6)
by
unknown
01:45
created

ShellCommand::environmentVariablesToString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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