Completed
Pull Request — develop (#132)
by
unknown
02:58
created

BaseCommand::getCLISubjects()   C

Complexity

Conditions 7
Paths 16

Size

Total Lines 29
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7.0796

Importance

Changes 0
Metric Value
dl 0
loc 29
ccs 15
cts 17
cp 0.8824
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 21
nc 16
nop 0
crap 7.0796
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
     * constructor
99
     *
100
     * should be called by all child classes' constructors to permit use of 
101
     * global configs, options and command arguments
102
     *
103
     * @param null|\GitElephant\Repository $repo The repo object to read
104
     */
105 129
    public function __construct(Repository $repo = null)
106
    {
107 129
        if (!is_null($repo)) {
108 97
            $this->addGlobalConfigs($repo->getGlobalConfigs());
109 97
            $this->addGlobalOptions($repo->getGlobalOptions());
110
            
111 97
            $arguments = $repo->getGlobalCommandArguments();
112 97
            if (!empty($arguments)) {
113 1
                foreach ($arguments as $argument) {
114 1
                    $this->addGlobalCommandArgument($argument);
115
                }
116
            }
117
        }
118 129
    }
119
120
    /**
121
     * Clear all previous variables
122
     */
123 115
    public function clearAll()
124
    {
125 115
        $this->commandName            = null;
126 115
        $this->configs                = array();
127 115
        $this->commandArguments       = array();
128 115
        $this->commandSubject         = null;
129 115
        $this->commandSubject2        = null;
130 115
        $this->path                   = null;
131 115
    }
132
133 119
    public static function getInstance(Repository $repo = null)
134
    {
135 119
        return new static($repo);
136
    }
137
138
    /**
139
     * Add the command name
140
     *
141
     * @param string $commandName the command name
142
     */
143 116
    protected function addCommandName($commandName)
144
    {
145 116
        $this->commandName = $commandName;
146 116
    }
147
148
    /**
149
     * Get command name
150
     *
151
     * @return string
152
     */
153 11
    protected function getCommandName()
154
    {
155 11
        return $this->commandName;
156
    }
157
158
    /**
159
     * Set Configs
160
     *
161
     * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" }
162
     */
163 3
    public function addConfigs($configs)
164
    {
165 3
        foreach ($configs as $config => $value) {
166 3
            $this->configs[$config] = $value;
167
        }
168 3
    }
169
170
    /**
171
     * Set global configs
172
     *
173
     * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" }
174
     */
175 97
    protected function addGlobalConfigs($configs)
176
    {
177 97
        if (!empty($configs)) {
178 1
            foreach ($configs as $config => $value) {
179 1
                $this->globalConfigs[$config] = $value;
180
            }
181
        }
182 97
    }
183
184
    /**
185
     * Set global option
186
     *
187
     * @param array|Map $options a global option
188
     */
189 97
    protected function addGlobalOptions($options)
190
    {
191 97
        if (!empty($options)) {
192 1
            foreach ($options as $name => $value) {
193 1
                $this->globalOptions[$name] = $value;
194
            }
195
        }
196 97
    }
197
198
    /**
199
     * Get Configs
200
     *
201
     * @return array
202
     */
203
    public function getConfigs()
204
    {
205
        return $this->configs;
206
    }
207
208
    /**
209
     * Add a command argument
210
     *
211
     * @param string $commandArgument the command argument
212
     */
213 106
    protected function addCommandArgument($commandArgument)
214
    {
215 106
        $this->commandArguments[] = $commandArgument;
216 106
    }
217
218
    /**
219
     * Add a global command argument
220
     *
221
     * @param string $commandArgument the command argument
222
     */
223 1
    protected function addGlobalCommandArgument($commandArgument)
224
    {
225 1
        if (!empty($commandArgument)) {
226 1
            $this->globalCommandArguments[] = $commandArgument;
227
        }
228 1
    }
229
230
    /**
231
     * Get all added command arguments
232
     *
233
     * @return array
234
     */
235 11
    protected function getCommandArguments()
236
    {
237 11
        return ($this->commandArguments) ? $this->commandArguments: array();
238
    }
239
240
    /**
241
     * Add a command subject
242
     *
243
     * @param SubCommandCommand|array|string $commandSubject the command subject
244
     */
245 105
    protected function addCommandSubject($commandSubject)
246
    {
247 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...
248 105
    }
249
250
    /**
251
     * Add a second command subject
252
     *
253
     * @param SubCommandCommand|array|string $commandSubject2 the second command subject
254
     */
255 22
    protected function addCommandSubject2($commandSubject2)
256
    {
257 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...
258 22
    }
259
260
    /**
261
     * Add a path to the git command
262
     *
263
     * @param string $path path
264
     */
265 19
    protected function addPath($path)
266
    {
267 19
        $this->path = $path;
268 19
    }
269
270
    /**
271
     * Normalize any valid option to its long name
272
     * an provide a structure that can be more intelligently
273
     * handled by other routines
274
     *
275
     * @param array $options       command options
276
     * @param array $switchOptions list of valid options that are switch like
277
     * @param array $valueOptions  list of valid options that must have a value assignment
278
     *
279
     * @return array Associative array of valid, normalized command options
280
     */
281 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...
282
    {
283 15
        $normalizedOptions = array();
284
285 15
        foreach ($options as $option) {
286 7
            if (array_key_exists($option, $switchOptions)) {
287 7
                $normalizedOptions[$switchOptions[$option]] = $switchOptions[$option];
288
            } else {
289 1
                $parts = preg_split('/([\s=])+/', $option, 2, PREG_SPLIT_DELIM_CAPTURE);
290 1
                if (count($parts)) {
291 1
                    $optionName = $parts[0];
292 1
                    if (in_array($optionName, $valueOptions)) {
293 1
                        $value = ($parts[1] == '=') ? $option : array($parts[0], $parts[2]);
294 7
                        $normalizedOptions[$optionName] = $value;
295
                    }
296
                }
297
            }
298
        }
299
300 15
        return $normalizedOptions;
301
    }
302
303
    /**
304
     * Get the current command
305
     *
306
     * @return string
307
     * @throws \RuntimeException
308
     */
309 117
    public function getCommand()
310
    {
311 117
        if (is_null($this->commandName)) {
312 1
            throw new \RuntimeException("You should pass a commandName to execute a command");
313
        }
314
315 116
        $command  = '';
316 116
        $command .= $this->getCLIConfigs();
317 116
        $command .= $this->getCLIGlobalOptions();
318 116
        $command .= $this->getCLICommandName();
319 116
        $command .= $this->getCLICommandArguments();
320 116
        $command .= $this->getCLISubjects();
321 116
        $command .= $this->getCLIPath();
322
323 116
        $command = preg_replace('/\\s{2,}/', ' ', $command);
324
325 116
        return trim($command);
326
    }
327
328
    /**
329
     * get a string of CLI-formatted command arguments
330
     *
331
     * @return string The command argument string
332
     */
333 117
    private function getCLICommandArguments()
334
    {
335 117
        $command = '';
336 117
        $combinedArguments = array_merge($this->globalCommandArguments, $this->commandArguments);
337 117
        if (count($combinedArguments) > 0) {
338 106
            $command .= ' ' . implode(' ', array_map('escapeshellarg', $combinedArguments));
339
        }
340 117
        return $command;
341
    }
342
343
    /**
344
     * get a string of CLI-formatted command name
345
     *
346
     * @return string The command name string
347
     */
348 117
    private function getCLICommandName()
349
    {
350 117
        return ' ' . $this->commandName;
351
    }
352
353
    /**
354
     * get a string of CLI-formatted configs
355
     *
356
     * @return string The config string
357
     */
358 117
    private function getCLIConfigs()
359
    {
360 117
        $command = '';
361 117
        $combinedConfigs = array_merge($this->globalConfigs, $this->configs);
362 117
        if (count($combinedConfigs)) {
363 4
            foreach ($combinedConfigs as $config => $value) {
364 4
                $command .= sprintf(
365 4
                    ' %s %s=%s',
366 4
                    escapeshellarg('-c'),
367 4
                    escapeshellarg($config),
368 4
                    escapeshellarg($value)
369
                );
370
            }
371
        }
372 117
        return $command;
373
    }
374
375
    /**
376
     * get a string of CLI-formatted global options
377
     *
378
     * @return string The global options string
379
     */
380 117
    private function getCLIGlobalOptions()
381
    {
382 117
        $command = '';
383 117
        if (count($this->globalOptions) > 0) {
384 1
            foreach ($this->globalOptions as $name => $value) {
385 1
                $command .= sprintf(' %s=%s', escapeshellarg($name), escapeshellarg($value));
386
            }
387
        }
388 117
        return $command;
389
    }
390
391
    /**
392
     * get a string of CLI-formatted path
393
     *
394
     * @return string The path string
395
     */
396 117
    private function getCLIPath()
397
    {
398 117
        $command = '';
399 117
        if (!is_null($this->path)) {
400 17
            $command .= sprintf(' -- %s', escapeshellarg($this->path));
401
        }
402 117
        return $command;
403
    }
404
405
    /**
406
     * get a string of CLI-formatted subjects
407
     *
408
     * @throws \RuntimeException
409
     * @return string The subjects string
410
     */
411 117
    private function getCLISubjects()
412
    {
413 117
        $command = '';
414 117
        if (!is_null($this->commandSubject)) {
415 106
            $command .= ' ';
416 106
            if ($this->commandSubject instanceof SubCommandCommand) {
417 10
                $command .= $this->commandSubject->getCommand();
418
            } else {
419 105
                if (is_array($this->commandSubject)) {
420 1
                    $command .= implode(' ', array_map('escapeshellarg', $this->commandSubject));
421
                } else {
422 104
                    $command .= escapeshellarg($this->commandSubject);
423
                }
424
            }
425
        }
426 117
        if (!is_null($this->commandSubject2)) {
427 23
            $command .= ' ';
428 23
            if ($this->commandSubject2 instanceof SubCommandCommand) {
429
                $command .= $this->commandSubject2->getCommand();
430
            } else {
431 23
                if (is_array($this->commandSubject2)) {
432
                    $command .= implode(' ', array_map('escapeshellarg', $this->commandSubject2));
433
                } else {
434 23
                    $command .= escapeshellarg($this->commandSubject2);
435
                }
436
            }
437
        }
438 117
        return $command;
439
    }
440
}
441