Completed
Push — master ( 3a5c6d...7f7360 )
by Emmanuel
02:10
created

ConfigGenerateCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 54
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 50
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 54
ccs 50
cts 50
cp 1
rs 9.6716
c 0
b 0
f 0
cc 1
eloc 50
nc 1
nop 0
crap 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * neuralyzer : Data Anonymization Library and CLI Tool
4
 *
5
 * PHP Version 7.0
6
 *
7
 * @author Emmanuel Dyan
8
 * @author Rémi Sauvat
9
 * @copyright 2017 Emmanuel Dyan
10
 *
11
 * @package edyan/neuralyzer
12
 *
13
 * @license GNU General Public License v2.0
14
 *
15
 * @link https://github.com/edyan/neuralyzer
16
 */
17
18
namespace Inet\Neuralyzer\Console\Commands;
19
20
use Symfony\Component\Console\Command\Command;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Symfony\Component\Console\Input\InputOption;
23
use Symfony\Component\Console\Output\OutputInterface;
24
use Symfony\Component\Console\Question\Question;
25
26
/**
27
 * Command to generate a config file from a DB
28
 */
29
class ConfigGenerateCommand extends Command
30
{
31
    use DBTrait;
32
33
    /**
34
     * Set the command shortcut to be used in configuration
35
     *
36
     * @var string
37
     */
38
    protected $command = 'config:generate';
39
40
41
    /**
42
     * Configure the command
43
     *
44
     * @return void
45
     */
46 4
    protected function configure()
47
    {
48
        // First command : Test the DB Connexion
49 4
        $this->setName($this->command)
50 4
             ->setDescription(
51 4
                 'Generate configuration for the Anonymizer'
52 4
             )->setHelp(
53 4
                 'This command will connect to a DB and extract a list of tables / fields to a yaml file' . PHP_EOL .
54 4
                 "Usage: ./bin/anon <info>{$this->command} -u app -p app -f anon.yml</info>"
55 4
             )->addOption(
56 4
                 'host',
57 4
                 null,
58 4
                 InputOption::VALUE_REQUIRED,
59 4
                 'Host',
60 4
                 '127.0.0.1'
61 4
             )->addOption(
62 4
                 'db',
63 4
                 'd',
64 4
                 InputOption::VALUE_REQUIRED,
65 4
                 'Database Name'
66 4
             )->addOption(
67 4
                 'user',
68 4
                 'u',
69 4
                 InputOption::VALUE_REQUIRED,
70 4
                 'User Name',
71
                 get_current_user()
72 4
             )->addOption(
73 4
                 'password',
74 4
                 'p',
75 4
                 InputOption::VALUE_REQUIRED,
76 4
                 "Password (or it'll be prompted)"
77 4
             )->addOption(
78 4
                 'file',
79 4
                 'f',
80 4
                 InputOption::VALUE_REQUIRED,
81 4
                 'File',
82 4
                 'anon.yml'
83 4
             )->addOption(
84 4
                 'protect',
85 4
                 null,
86 4
                 InputOption::VALUE_NONE,
87 4
                 'Protect IDs and other fields'
88 4
             )->addOption(
89 4
                 'ignore-table',
90 4
                 null,
91 4
                 InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
92 4
                 'Table to ignore. Can be repeated'
93 4
             )->addOption(
94 4
                 'ignore-field',
95 4
                 null,
96 4
                 InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
97 4
                 'Field to ignore. Regexp in the form "table.field". Can be repeated'
98
             );
99 4
    }
100
101
    /**
102
     * Execute the command
103
     *
104
     * @param InputInterface  $input
105
     * @param OutputInterface $output
106
     *
107
     * @return void
108
     */
109
    protected function execute(InputInterface $input, OutputInterface $output)
110
    {
111
        $password = $input->getOption('password');
112
        if (is_null($password)) {
113
            $question = new Question('Password: ');
114
            $question->setHidden(true)->setHiddenFallback(false);
115
116
            $password = $this->getHelper('question')->ask($input, $output, $question);
0 ignored issues
show
Bug introduced by
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...
117
        }
118
119
        $this->connectToDB(
120
            $input->getOption('host'),
121
            $input->getOption('db'),
122
            $input->getOption('user'),
123
            $password
124
        );
125
126
        $ignoreFields = $input->getOption('ignore-field');
127
128
        $writer = new \Inet\Neuralyzer\Configuration\Writer;
129
        $writer->protectCols($input->getOption('protect'));
130
131
        // Override the protection if fields are defined
132
        if (!empty($ignoreFields)) {
133
            $writer->protectCols(true);
134
            $writer->setProtectedCols($ignoreFields);
135
        }
136
137
        $writer->setIgnoredTables($input->getOption('ignore-table'));
138
        $data = $writer->generateConfFromDB($this->pdo, new \Inet\Neuralyzer\Guesser);
139
        $writer->save($data, $input->getOption('file'));
140
141
        $output->writeln('<comment>Configuration written to ' . $input->getOption('file') . '</comment>');
142
    }
143
}
144