Completed
Pull Request — develop (#147)
by
unknown
02:01
created

BaseCommand::addPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * GitElephant - An abstraction layer for git written in PHP
4
 * Copyright (C) 2013  Matteo Giachino
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see [http://www.gnu.org/licenses/].
18
 */
19
20
namespace GitElephant\Command;
21
22
use \GitElephant\Repository;
23
use \PhpCollection\Map;
24
25
/**
26
 * BaseCommand
27
 *
28
 * The base class for all the command generators
29
 *
30
 * @author Matteo Giachino <[email protected]>
31
 */
32
class BaseCommand
33
{
34
    /**
35
     * the command name
36
     *
37
     * @var string
38
     */
39
    private $commandName = null;
40
41
    /**
42
     * config options
43
     *
44
     * @var array
45
     */
46
    private $configs = array();
47
48
    /**
49
     * global configs
50
     *
51
     * @var array
52
     */
53
    private $globalConfigs = array();
54
55
    /**
56
     * global options
57
     *
58
     * @var array
59
     */
60
    private $globalOptions = array();
61
62
    /**
63
     * the command arguments
64
     *
65
     * @var array
66
     */
67
    private $commandArguments = array();
68
69
    /**
70
     * the global command arguments
71
     *
72
     * @var array
73
     */
74
    private $globalCommandArguments = array();
75
76
    /**
77
     * the command subject
78
     *
79
     * @var string|SubCommandCommand
80
     */
81
    private $commandSubject = null;
82
83
    /**
84
     * the command second subject (i.e. for branch)
85
     *
86
     * @var string|SubCommandCommand
87
     */
88
    private $commandSubject2 = null;
89
90
    /**
91
     * the path
92
     *
93
     * @var string
94
     */
95
    private $path = null;
96
97
    /**
98
     * @var string
99
     */
100
    private $binaryVersion;
101
102
    /**
103
     * constructor
104
     *
105
     * should be called by all child classes' constructors to permit use of 
106
     * global configs, options and command arguments
107
     *
108
     * @param null|\GitElephant\Repository $repo The repo object to read
109
     */
110 130
    public function __construct(Repository $repo = null)
111
    {
112 130
        if (!is_null($repo)) {
113 98
            $this->addGlobalConfigs($repo->getGlobalConfigs());
114 98
            $this->addGlobalOptions($repo->getGlobalOptions());
115
            
116 98
            $arguments = $repo->getGlobalCommandArguments();
117 98
            if (!empty($arguments)) {
118 1
                foreach ($arguments as $argument) {
119 1
                    $this->addGlobalCommandArgument($argument);
120
                }
121
            }
122 98
            $this->binaryVersion = $repo->getCaller()->getBinaryVersion();
123
        }
124 130
    }
125
126
    /**
127
     * Clear all previous variables
128
     */
129 115
    public function clearAll()
130
    {
131 115
        $this->commandName            = null;
132 115
        $this->configs                = array();
133 115
        $this->commandArguments       = array();
134 115
        $this->commandSubject         = null;
135 115
        $this->commandSubject2        = null;
136 115
        $this->path                   = null;
137 115
        $this->binaryVersion          = null;
138 115
    }
139
140 120
    public static function getInstance(Repository $repo = null)
141
    {
142 120
        return new static($repo);
143
    }
144
145
    /**
146
     * Add the command name
147
     *
148
     * @param string $commandName the command name
149
     */
150 116
    protected function addCommandName($commandName)
151
    {
152 116
        $this->commandName = $commandName;
153 116
    }
154
155
    /**
156
     * Get command name
157
     *
158
     * @return string
159
     */
160 11
    protected function getCommandName()
161
    {
162 11
        return $this->commandName;
163
    }
164
165
    /**
166
     * Set Configs
167
     *
168
     * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" }
169
     */
170 3
    public function addConfigs($configs)
171
    {
172 3
        foreach ($configs as $config => $value) {
173 3
            $this->configs[$config] = $value;
174
        }
175 3
    }
176
177
    /**
178
     * Set global configs
179
     *
180
     * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" }
181
     */
182 98
    protected function addGlobalConfigs($configs)
183
    {
184 98
        if (!empty($configs)) {
185 1
            foreach ($configs as $config => $value) {
186 1
                $this->globalConfigs[$config] = $value;
187
            }
188
        }
189 98
    }
190
191
    /**
192
     * Set global option
193
     *
194
     * @param array|Map $options a global option
195
     */
196 98
    protected function addGlobalOptions($options)
197
    {
198 98
        if (!empty($options)) {
199 1
            foreach ($options as $name => $value) {
200 1
                $this->globalOptions[$name] = $value;
201
            }
202
        }
203 98
    }
204
205
    /**
206
     * Get Configs
207
     *
208
     * @return array
209
     */
210
    public function getConfigs()
211
    {
212
        return $this->configs;
213
    }
214
215
    /**
216
     * Add a command argument
217
     *
218
     * @param string $commandArgument the command argument
219
     */
220 106
    protected function addCommandArgument($commandArgument)
221
    {
222 106
        $this->commandArguments[] = $commandArgument;
223 106
    }
224
225
    /**
226
     * Add a global command argument
227
     *
228
     * @param string $commandArgument the command argument
229
     */
230 1
    protected function addGlobalCommandArgument($commandArgument)
231
    {
232 1
        if (!empty($commandArgument)) {
233 1
            $this->globalCommandArguments[] = $commandArgument;
234
        }
235 1
    }
236
237
    /**
238
     * Get all added command arguments
239
     *
240
     * @return array
241
     */
242 11
    protected function getCommandArguments()
243
    {
244 11
        return ($this->commandArguments) ? $this->commandArguments: array();
245
    }
246
247
    /**
248
     * Add a command subject
249
     *
250
     * @param SubCommandCommand|array|string $commandSubject the command subject
251
     */
252 105
    protected function addCommandSubject($commandSubject)
253
    {
254 105
        $this->commandSubject = $commandSubject;
0 ignored issues
show
Documentation Bug introduced by
It seems like $commandSubject can also be of type array. However, the property $commandSubject is declared as type string|object<GitElephan...mand\SubCommandCommand>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
255 105
    }
256
257
    /**
258
     * Add a second command subject
259
     *
260
     * @param SubCommandCommand|array|string $commandSubject2 the second command subject
261
     */
262 22
    protected function addCommandSubject2($commandSubject2)
263
    {
264 22
        $this->commandSubject2 = $commandSubject2;
0 ignored issues
show
Documentation Bug introduced by
It seems like $commandSubject2 can also be of type array. However, the property $commandSubject2 is declared as type string|object<GitElephan...mand\SubCommandCommand>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
265 22
    }
266
267
    /**
268
     * Add a path to the git command
269
     *
270
     * @param string $path path
271
     */
272 19
    protected function addPath($path)
273
    {
274 19
        $this->path = $path;
275 19
    }
276
277
    /**
278
     * Normalize any valid option to its long name
279
     * an provide a structure that can be more intelligently
280
     * handled by other routines
281
     *
282
     * @param array $options       command options
283
     * @param array $switchOptions list of valid options that are switch like
284
     * @param array $valueOptions  list of valid options that must have a value assignment
285
     *
286
     * @return array Associative array of valid, normalized command options
287
     */
288 15
    public function normalizeOptions(Array $options = array(), Array $switchOptions = array(), $valueOptions = array())
0 ignored issues
show
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected array, but found Array.
Loading history...
289
    {
290 15
        $normalizedOptions = array();
291
292 15
        foreach ($options as $option) {
293 7
            if (array_key_exists($option, $switchOptions)) {
294 7
                $normalizedOptions[$switchOptions[$option]] = $switchOptions[$option];
295
            } else {
296 1
                $parts = preg_split('/([\s=])+/', $option, 2, PREG_SPLIT_DELIM_CAPTURE);
297 1
                if (count($parts)) {
298 1
                    $optionName = $parts[0];
299 1
                    if (in_array($optionName, $valueOptions)) {
300 1
                        $value = ($parts[1] == '=') ? $option : array($parts[0], $parts[2]);
301 7
                        $normalizedOptions[$optionName] = $value;
302
                    }
303
                }
304
            }
305
        }
306
307 15
        return $normalizedOptions;
308
    }
309
310
    /**
311
     * Get the current command
312
     *
313
     * @return string
314
     * @throws \RuntimeException
315
     */
316 117
    public function getCommand()
317
    {
318 117
        if (is_null($this->commandName)) {
319 1
            throw new \RuntimeException("You should pass a commandName to execute a command");
320
        }
321
322 116
        $command  = '';
323 116
        $command .= $this->getCLIConfigs();
324 116
        $command .= $this->getCLIGlobalOptions();
325 116
        $command .= $this->getCLICommandName();
326 116
        $command .= $this->getCLICommandArguments();
327 116
        $command .= $this->getCLISubjects();
328 116
        $command .= $this->getCLIPath();
329
330 116
        $command = preg_replace('/\\s{2,}/', ' ', $command);
331
332 116
        return trim($command);
333
    }
334
335
    /**
336
     * get a string of CLI-formatted command arguments
337
     *
338
     * @return string The command argument string
339
     */
340 117
    private function getCLICommandArguments()
341
    {
342 117
        $command = '';
343 117
        $combinedArguments = array_merge($this->globalCommandArguments, $this->commandArguments);
344 117
        if (count($combinedArguments) > 0) {
345 106
            $command .= ' ' . implode(' ', array_map('escapeshellarg', $combinedArguments));
346
        }
347 117
        return $command;
348
    }
349
350
    /**
351
     * get a string of CLI-formatted command name
352
     *
353
     * @return string The command name string
354
     */
355 117
    private function getCLICommandName()
356
    {
357 117
        return ' ' . $this->commandName;
358
    }
359
360
    /**
361
     * get a string of CLI-formatted configs
362
     *
363
     * @return string The config string
364
     */
365 117
    private function getCLIConfigs()
366
    {
367 117
        $command = '';
368 117
        $combinedConfigs = array_merge($this->globalConfigs, $this->configs);
369 117
        if (count($combinedConfigs)) {
370 4
            foreach ($combinedConfigs as $config => $value) {
371 4
                $command .= sprintf(
372 4
                    ' %s %s=%s',
373 4
                    escapeshellarg('-c'),
374 4
                    escapeshellarg($config),
375 4
                    escapeshellarg($value)
376
                );
377
            }
378
        }
379 117
        return $command;
380
    }
381
382
    /**
383
     * get a string of CLI-formatted global options
384
     *
385
     * @return string The global options string
386
     */
387 117
    private function getCLIGlobalOptions()
388
    {
389 117
        $command = '';
390 117
        if (count($this->globalOptions) > 0) {
391 1
            foreach ($this->globalOptions as $name => $value) {
392 1
                $command .= sprintf(' %s=%s', escapeshellarg($name), escapeshellarg($value));
393
            }
394
        }
395 117
        return $command;
396
    }
397
398
    /**
399
     * get a string of CLI-formatted path
400
     *
401
     * @return string The path string
402
     */
403 117
    private function getCLIPath()
404
    {
405 117
        $command = '';
406 117
        if (!is_null($this->path)) {
407 17
            $command .= sprintf(' -- %s', escapeshellarg($this->path));
408
        }
409 117
        return $command;
410
    }
411
412
    /**
413
     * get a string of CLI-formatted subjects
414
     *
415
     * @throws \RuntimeException
416
     * @return string The subjects string
417
     */
418 117
    private function getCLISubjects()
419
    {
420 117
        $command = '';
421 117
        if (!is_null($this->commandSubject)) {
422 106
            $command .= ' ';
423 106
            if ($this->commandSubject instanceof SubCommandCommand) {
424 10
                $command .= $this->commandSubject->getCommand();
425
            } else {
426 105
                if (is_array($this->commandSubject)) {
427 1
                    $command .= implode(' ', array_map('escapeshellarg', $this->commandSubject));
428
                } else {
429 104
                    $command .= escapeshellarg($this->commandSubject);
430
                }
431
            }
432
        }
433 117
        if (!is_null($this->commandSubject2)) {
434 23
            $command .= ' ';
435 23
            if ($this->commandSubject2 instanceof SubCommandCommand) {
436
                $command .= $this->commandSubject2->getCommand();
437
            } else {
438 23
                if (is_array($this->commandSubject2)) {
439
                    $command .= implode(' ', array_map('escapeshellarg', $this->commandSubject2));
440
                } else {
441 23
                    $command .= escapeshellarg($this->commandSubject2);
442
                }
443
            }
444
        }
445 117
        return $command;
446
    }
447
448
    /**
449
     * @return string|null
450
     */
451 1
    public function getBinaryVersion()
452
    {
453 1
        return $this->binaryVersion;
454
    }
455
}
456