Completed
Pull Request — develop (#147)
by
unknown
12:57
created

BaseCommand::__construct()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

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