BaseOptionHelper   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 96.77%

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 3
dl 0
loc 131
ccs 30
cts 31
cp 0.9677
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
getQuestion() 0 1 ?
A __construct() 0 6 1
A setAllowedValues() 0 6 1
A setErrorMessage() 0 6 1
A setDefaultValue() 0 6 1
C setOption() 0 27 7
A ask() 0 4 1
1
<?php
2
3
namespace Rj\FrontendBundle\Command\Options;
4
5
use Symfony\Component\Console\Command\Command;
6
use Symfony\Component\Console\Input\InputInterface;
7
use Symfony\Component\Console\Output\OutputInterface;
8
use Symfony\Component\Console\Question\Question;
9
10
abstract class BaseOptionHelper
11
{
12
    /**
13
     * @var mixed
14
     */
15
    protected $defaultValue = 0;
16
17
    /**
18
     * @var array
19
     */
20
    protected $allowedValues = [];
21
22
    /**
23
     * @var string|null
24
     */
25
    protected $errorMessage = null;
26
27
    /**
28
     * @var Command
29
     */
30
    private $command;
31
32
    /**
33
     * @var InputInterface
34
     */
35
    private $input;
36
37
    /**
38
     * @var OutputInterface
39
     */
40
    private $output;
41
42
    /**
43
     * @param string $question
44
     *
45
     * @return Question
46
     */
47
    abstract protected function getQuestion($question);
48
49
    /**
50
     * @param Command         $command
51
     * @param InputInterface  $input
52
     * @param OutputInterface $output
53
     */
54 2
    public function __construct(Command $command, InputInterface $input, OutputInterface $output)
55
    {
56 2
        $this->command = $command;
57 2
        $this->input = $input;
58 2
        $this->output = $output;
59 2
    }
60
61
    /**
62
     * @param array $allowedValues
63
     *
64
     * @return $this
65
     */
66 2
    public function setAllowedValues(array $allowedValues)
67
    {
68 2
        $this->allowedValues = $allowedValues;
69
70 2
        return $this;
71
    }
72
73
    /**
74
     * @param string $errorMessage
75
     *
76
     * @return $this
77
     */
78 2
    public function setErrorMessage($errorMessage)
79
    {
80 2
        $this->errorMessage = $errorMessage;
81
82 2
        return $this;
83
    }
84
85
    /**
86
     * @param mixed $defaultValue
87
     *
88
     * @return $this
89
     */
90 2
    public function setDefaultValue($defaultValue)
91
    {
92 2
        $this->defaultValue = $defaultValue;
93
94 2
        return $this;
95
    }
96
97
    /**
98
     * @param string $name
99
     * @param string $question
100
     *
101
     * @return string|bool
102
     */
103 2
    public function setOption($name, $question)
104
    {
105 2
        $selection = $this->input->getOption($name);
106 2
        $allowed = $this->allowedValues;
107 2
        $error = $this->errorMessage;
108
109 2
        if (null !== $selection && !empty($allowed) && !in_array($selection, $allowed)) {
110 2
            $this->output->writeln(sprintf("<error>$error</error>", $selection));
111 2
            $selection = null;
112
        }
113
114 2
        if (null === $selection) {
115 2
            $selection = $this->ask($this->getQuestion($question));
116
        }
117
118 2
        if ($selection === 'false') {
119 2
            $selection = false;
120
        }
121
122 2
        if ($selection === 'true') {
123
            $selection = true;
124
        }
125
126 2
        $this->input->setOption($name, $selection);
127
128 2
        return $selection;
129
    }
130
131
    /**
132
     * @param Question $question
133
     *
134
     * @return mixed
135
     */
136 2
    private function ask(Question $question)
137
    {
138 2
        return $this->command->getHelper('question')->ask($this->input, $this->output, $question);
0 ignored issues
show
Bug introduced by Paulo Rodrigues Pinto
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method ask() does only exist in the following implementations of said interface: Symfony\Component\Console\Helper\QuestionHelper, Symfony\Component\Consol...r\SymfonyQuestionHelper.

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...
139
    }
140
}
141