Completed
Push — develop ( 8fda15...dbbcf5 )
by Jaap
14s
created

UpdateCommand::execute()   B

Complexity

Conditions 8
Paths 38

Size

Total Lines 55
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
cc 8
eloc 37
nc 38
nop 2
dl 0
loc 55
ccs 0
cts 45
cp 0
crap 72
rs 7.4033
c 0
b 0
f 0

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
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2018 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor\Application\Console\Command\Phar;
13
14
use \Exception;
15
use Humbug\SelfUpdate\Strategy\GithubStrategy;
16
use Humbug\SelfUpdate\Updater;
17
use phpDocumentor\Application;
18
use Symfony\Component\Console\Command\Command;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
23
/**
24
 * Updates phpDocumentor.phar to the latest version.
25
 *
26
 * ```
27
 * $ php phpDocumentor.phar phar:update [-m|--major] [-p|--pre] [version]
28
 * ```
29
 */
30
class UpdateCommand extends Command
31
{
32
    const PHAR_URL = 'https://github.com/phpDocumentor/phpDocumentor2/releases/latest';
33
34
    /**
35
     * Initializes this command and sets the name, description, options and arguments.
36
     */
37
    protected function configure()
38
    {
39
        $this->setName('phar:update')
40
            ->setAliases(['selfupdate', 'self-update'])
41
            ->setDescription('Updates the binary with the latest version.')
42
            ->addOption(
43
                'rollback',
44
                null,
45
                InputOption::VALUE_NONE,
46
                'Rollsback the updated binary to the last version.'
47
            )
48
            ->addOption('pre', 'p', InputOption::VALUE_NONE, 'Allow pre-release version update');
49
    }
50
51
    /**
52
     * Executes the business logic involved with this command.
53
     *
54
     * @return int
55
     */
56
    protected function execute(InputInterface $input, OutputInterface $output)
57
    {
58
        $output->writeln('Looking for updates...');
59
60
        $allowPreRelease = $input->getOption('pre');
61
62
        if (PHP_VERSION_ID < 50600) {
63
            $message = 'Self updating is not available in PHP versions under 5.6.' . "\n";
64
            $message .= 'The latest version can be found at ' . self::PHAR_URL;
65
            $output->writeln(sprintf('<error>%s</error>', $message));
66
            return 1;
67
        } elseif (Application::VERSION() === ('@package_version@')) {
68
            $output->writeln('<error>Self updating has been disabled in source version.</error>');
69
            return 1;
70
        }
71
72
        $exitCode = 1;
73
74
        $updater = new Updater();
75
        $updater->setStrategy(Updater::STRATEGY_GITHUB);
76
        $updater->getStrategy()->setPackageName('phpdocumentor/phpDocumentor2');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Humbug\SelfUpdate\Strategy\StrategyInterface as the method setPackageName() does only exist in the following implementations of said interface: Humbug\SelfUpdate\Strategy\GithubStrategy, Humbug\Test\SelfUpdate\GithubTestStrategy.

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...
77
        $updater->getStrategy()->setPharName('phpDocumentor.phar');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Humbug\SelfUpdate\Strategy\StrategyInterface as the method setPharName() does only exist in the following implementations of said interface: Humbug\SelfUpdate\Strategy\GithubStrategy, Humbug\Test\SelfUpdate\GithubTestStrategy.

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...
78
        $updater->getStrategy()->getCurrentLocalVersion(Application::VERSION());
0 ignored issues
show
Documentation introduced by
\phpDocumentor\Application::VERSION() is of type string, but the function expects a object<Humbug\SelfUpdate\Updater>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
79
80
        if ($allowPreRelease) {
81
            $updater->getStrategy()->setStability(GithubStrategy::ANY);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Humbug\SelfUpdate\Strategy\StrategyInterface as the method setStability() does only exist in the following implementations of said interface: Humbug\SelfUpdate\Strategy\GithubStrategy, Humbug\Test\SelfUpdate\GithubTestStrategy.

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...
82
        }
83
84
        try {
85
            if ($input->getOption('rollback')) {
86
                $output->writeln('Rolling back to previous version...');
87
                $result = $updater->rollback();
88
            } else {
89
                if (!$updater->hasUpdate()) {
90
                    $output->writeln('No new version available.');
91
                    return 0;
92
                }
93
94
                $output->writeln('Updating to newer version...');
95
                $result = $updater->update();
96
            }
97
98
            if ($result) {
99
                $new = $updater->getNewVersion();
100
                $old = $updater->getOldVersion();
101
102
                $output->writeln(sprintf('Updated from %s to %s', $old, $new));
103
                $exitCode = 0;
104
            }
105
        } catch (Exception $e) {
106
            $output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
107
        }
108
109
        return $exitCode;
110
    }
111
}
112