LimoncelloCommand   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 10

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 8
dl 0
loc 121
ccs 38
cts 38
cp 1
rs 10
c 0
b 0
f 0
lcom 2
cbo 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 1
A configure() 0 24 3
A execute() 0 29 4
1
<?php declare(strict_types=1);
2
3
namespace Limoncello\Commands;
4
5
/**
6
 * Copyright 2015-2019 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Composer\Command\BaseCommand;
22
use Exception;
23
use Limoncello\Commands\Traits\CommandSerializationTrait;
24
use Limoncello\Commands\Traits\CommandTrait;
25
use Limoncello\Commands\Wrappers\DataArgumentWrapper;
26
use Limoncello\Commands\Wrappers\DataOptionWrapper;
27
use Limoncello\Contracts\Container\ContainerInterface as LimoncelloContainerInterface;
28
use Limoncello\Contracts\Exceptions\ThrowableHandlerInterface;
29
use Symfony\Component\Console\Input\InputInterface;
30
use Symfony\Component\Console\Output\OutputInterface;
31
use function assert;
32
33
/**
34
 * @package Limoncello\Commands
35
 *
36
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
37
 */
38
class LimoncelloCommand extends BaseCommand
39
{
40
    use CommandTrait, CommandSerializationTrait, ExecuteCommandTrait;
41
42
    /**
43
     * @var string
44
     */
45
    private $description;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
46
47
    /**
48
     * @var string
49
     */
50
    private $help;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
51
52
    /**
53
     * @var array
54
     */
55
    private $arguments;
56
57
    /**
58
     * @var array
59
     */
60
    private $options;
61
62
    /**
63
     * @var callable|array
64
     */
65
    private $callable;
66
67
    /**
68
     * @param string $name
69
     * @param string $description
70
     * @param string $help
71
     * @param array  $arguments
72 4
     * @param array  $options
73
     * @param array  $callable
74
     */
75
    public function __construct(
76
        string $name,
77
        string $description,
78
        string $help,
79
        array $arguments,
80 4
        array $options,
81 4
        array $callable
82 4
    ) {
83 4
        $this->description = $description;
84 4
        $this->help        = $help;
85
        $this->arguments   = $arguments;
86
        $this->options     = $options;
87
        $this->callable    = $callable;
88 4
89
        // it is important to call the parent constructor after
90
        // data init as it calls `configure` method.
91
        parent::__construct($name);
92
    }
93
94 4
    /**
95
     * @inheritdoc
96 4
     */
97
    public function configure()
98
    {
99 4
        parent::configure();
100 4
101
        $this
102 4
            ->setDescription($this->description)
103 3
            ->setHelp($this->help);
104 3
105
        foreach ($this->arguments as $data) {
106
            $arg = new DataArgumentWrapper($data);
107 4
            $this->addArgument($arg->getName(), $arg->getMode(), $arg->getDescription(), $arg->getDefault());
108 3
        }
109 3
110 3
        foreach ($this->options as $data) {
111 3
            $opt = new DataOptionWrapper($data);
112 3
            $this->addOption(
113 3
                $opt->getName(),
114 3
                $opt->getShortcut(),
115
                $opt->getMode(),
116
                $opt->getDescription(),
117
                $opt->getDefault()
118
            );
119
        }
120
    }
121
122
    /** @noinspection PhpMissingParentCallCommonInspection
123
     * @inheritdoc
124
     *
125
     * @throws Exception
126 3
     *
127
     * @SuppressWarnings(PHPMD.ElseExpression)
128 3
     */
129
    public function execute(InputInterface $input, OutputInterface $output)
130
    {
131
        $container = null;
132 3
        try {
133 2
            // There is a tiny hack here. We need editable container and we know that at this point
134
            // container still can be edited so we cast it to `LimoncelloContainerInterface`.
135 2
            $container = $this->createContainer($this->getComposer());
0 ignored issues
show
Bug introduced by
It seems like $this->getComposer() can be null; however, createContainer() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
136 2
            assert($container instanceof LimoncelloContainerInterface);
137 2
138
            $this->executeCommand($this->getName(), $this->callable, $this->wrapIo($input, $output), $container);
139 1
        } catch (Exception $exception) {
140 1
            if ($container !== null && $container->has(ThrowableHandlerInterface::class) === true) {
141
                /** @var ThrowableHandlerInterface $handler */
142 1
                $handler  = $container->get(ThrowableHandlerInterface::class);
143
                $response = $handler->createResponse($exception, $container);
144 1
145 1
                $output->writeln((string)$response->getBody());
146 1
            } else {
147 1
                $message = $exception->getMessage();
148
                $file    = $exception->getFile();
149 1
                $line    = $exception->getLine();
150
                $trace   = $exception->getTraceAsString();
151
152 2
                $output->writeln("$message at $file#$line" . PHP_EOL . $trace);
153
            }
154
155
            throw $exception;
156
        }
157
    }
158
}
159