AbstractCommandAdapter::getAdaptedCommand()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the webmozart/console package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webmozart\Console\Adapter;
13
14
use Symfony\Component\Console\Application;
15
use Symfony\Component\Console\Command\Command;
16
use Symfony\Component\Console\Helper\HelperSet;
17
use Symfony\Component\Console\Input\InputDefinition;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Webmozart\Assert\Assert;
21
22
/**
23
 * Adapts a `Command` instance of this package to Symfony's {@link Command} API.
24
 *
25
 * @since  1.0
26
 *
27
 * @author Bernhard Schussek <[email protected]>
28
 */
29
abstract class AbstractCommandAdapter extends Command
30
{
31
    /**
32
     * @var \Webmozart\Console\Api\Command\Command
33
     */
34
    private $adaptedCommand;
35
36
    /**
37
     * Creates the adapter.
38
     *
39
     * @param \Webmozart\Console\Api\Command\Command $adaptedCommand The adapted command.
40
     * @param Application                            $application    The application.
41
     */
42 15
    public function __construct(\Webmozart\Console\Api\Command\Command $adaptedCommand, Application $application)
43
    {
44 15
        parent::setName($adaptedCommand->getName());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setName() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->setName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
45
46 15
        parent::__construct();
47
48 15
        $this->adaptedCommand = $adaptedCommand;
49
50 15
        $config = $adaptedCommand->getConfig();
51
52 15
        parent::setDefinition(new ArgsFormatInputDefinition($this->adaptedCommand->getArgsFormat()));
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setDefinition() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->setDefinition().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
53 15
        parent::setApplication($application);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setApplication() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->setApplication().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
54 15
        parent::setDescription($config->getDescription());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setDescription() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->setDescription().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
55 15
        parent::setHelp($config->getHelp());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setHelp() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->setHelp().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
56 15
        parent::setAliases($adaptedCommand->getAliases());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setAliases() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->setAliases().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
57
58 15
        if ($helperSet = $config->getHelperSet()) {
59 15
            parent::setHelperSet($helperSet);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setHelperSet() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->setHelperSet().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
60
        }
61 15
    }
62
63
    /**
64
     * Returns the adapted command.
65
     *
66
     * @return Command The adapted command.
0 ignored issues
show
Documentation introduced by
Should the return type not be \Webmozart\Console\Api\Command\Command?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
67
     */
68 1
    public function getAdaptedCommand()
69
    {
70 1
        return $this->adaptedCommand;
71
    }
72
73
    /**
74
     * Does nothing.
75
     *
76
     * @param Application $application The application.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $application not be null|Application?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
77
     *
78
     * @return static The current instance.
79
     */
80 13
    public function setApplication(Application $application = null)
81
    {
82 13
        return $this;
83
    }
84
85
    /**
86
     * Does nothing.
87
     *
88
     * @param HelperSet $helperSet The helper set.
89
     *
90
     * @return static The current instance.
91
     */
92 15
    public function setHelperSet(HelperSet $helperSet)
93
    {
94 15
        return $this;
95
    }
96
97
    /**
98
     * Does nothing.
99
     *
100
     * @param array|InputDefinition $definition The definition
101
     *
102
     * @return static The current instance.
103
     */
104
    public function setDefinition($definition)
105
    {
106
        return $this;
107
    }
108
109
    /**
110
     * Does nothing.
111
     *
112
     * @param string $name The name.
113
     *
114
     * @return static The current instance.
115
     */
116
    public function setName($name)
117
    {
118
        return $this;
119
    }
120
121
    /**
122
     * Does nothing.
123
     *
124
     * @param string $title The process title.
125
     *
126
     * @return static The current instance.
127
     */
128
    public function setProcessTitle($title)
129
    {
130
        return $this;
131
    }
132
133
    /**
134
     * Does nothing.
135
     *
136
     * @param string $description The description.
137
     *
138
     * @return static The current instance.
139
     */
140
    public function setDescription($description)
141
    {
142
        return $this;
143
    }
144
145
    /**
146
     * Does nothing.
147
     *
148
     * @param string $help The help.
149
     *
150
     * @return static The current instance.
151
     */
152
    public function setHelp($help)
153
    {
154
        return $this;
155
    }
156
157
    /**
158
     * Does nothing.
159
     *
160
     * @param string[] $aliases The aliases.
161
     *
162
     * @return static The current instance.
163
     */
164
    public function setAliases($aliases)
165
    {
166
        return $this;
167
    }
168
169
    /**
170
     * Does nothing.
171
     *
172
     * @param bool $mergeArgs
173
     *
174
     * @return static The current instance.
175
     */
176 12
    public function mergeApplicationDefinition($mergeArgs = true)
177
    {
178 12
        return $this;
179
    }
180
181
    /**
182
     * Does nothing.
183
     *
184
     * @param string $name
185
     * @param null   $mode
186
     * @param string $description
187
     * @param null   $default
188
     *
189
     * @return static The current instance.
190
     */
191
    public function addArgument($name, $mode = null, $description = '', $default = null)
192
    {
193
        return $this;
194
    }
195
196
    /**
197
     * Does nothing.
198
     *
199
     * @param string $name
200
     * @param null   $shortcut
201
     * @param null   $mode
202
     * @param string $description
203
     * @param null   $default
204
     *
205
     * @return static The current instance.
206
     */
207
    public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
208
    {
209
        return $this;
210
    }
211
212
    /**
213
     * {@inheritdoc}
214
     */
215 15
    public function isEnabled()
216
    {
217 15
        return $this->adaptedCommand->getConfig()->isEnabled();
218
    }
219
220
    /**
221
     * Executes the command.
222
     *
223
     * @param InputInterface  $input  The console input.
224
     * @param OutputInterface $output The console output.
225
     *
226
     * @return int The exit status.
227
     */
228
    public function run(InputInterface $input, OutputInterface $output)
229
    {
230
        /* @var ArgsInput $input */
231
        /* @var IOOutput $output */
232
        Assert::isInstanceOf($input, 'Webmozart\Console\Adapter\ArgsInput');
233
        Assert::isInstanceOf($output, 'Webmozart\Console\Adapter\IOOutput');
234
235
        return $this->adaptedCommand->handle($input->getArgs(), $output->getIO());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Input\InputInterface as the method getArgs() does only exist in the following implementations of said interface: Webmozart\Console\Adapter\ArgsInput.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
236
    }
237
}
238
239 1
if (method_exists('Symfony\Component\Console\Command\Command', 'asText')) {
240
    // Symfony 2.0 compatible definition
241
    class CommandAdapter extends AbstractCommandAdapter
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
242
    {
243
        /**
244
         * Does nothing.
245
         *
246
         * @param callable $code The code.
247
         *
248
         * @return static The current instance.
249
         */
250
        public function setCode($code)
251
        {
252
            return $this;
253
        }
254
    }
255
} else {
256
    // Symfony 3.0 compatible definition
257
    class CommandAdapter extends AbstractCommandAdapter
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Comprehensibility Best Practice introduced by
The type Webmozart\Console\Adapter\CommandAdapter has been defined more than once; this definition is ignored, only the first definition in this file (L241-254) is considered.

This check looks for classes that have been defined more than once in the same file.

If you can, we would recommend to use standard object-oriented programming techniques. For example, to avoid multiple types, it might make sense to create a common interface, and then multiple, different implementations for that interface.

This also has the side-effect of providing you with better IDE auto-completion, static analysis and also better OPCode caching from PHP.

Loading history...
258
    {
259
        /**
260
         * Does nothing.
261
         *
262
         * @param callable $code The code.
263
         *
264
         * @return static The current instance.
265
         */
266
        public function setCode(callable $code)
267
        {
268
            return $this;
269
        }
270
    }
271
}
272