Completed
Push — master ( 5f27ef...d1e65c )
by grégoire
12:16 queued 07:49
created

sources/lib/Command/GenerateForRelation.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 * This file is part of Pomm's Cli package.
4
 *
5
 * (c) 2014 - 2015 Grégoire HUBERT <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PommProject\Cli\Command;
11
12
use PommProject\Foundation\ParameterHolder;
13
use PommProject\ModelManager\Generator\EntityGenerator;
14
use PommProject\ModelManager\Generator\ModelGenerator;
15
use PommProject\ModelManager\Generator\StructureGenerator;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Input\InputOption;
19
use Symfony\Component\Console\Output\OutputInterface;
20
21
/**
22
 * GenerateForRelation
23
 *
24
 * Generate a Structure, a model and an entity class if they do not already
25
 * exist (unless --force is specified).
26
 *
27
 * @package   Cli
28
 * @copyright 2014 - 2015 Grégoire HUBERT
29
 * @author    Grégoire HUBERT
30
 * @license   X11 {@link http://opensource.org/licenses/mit-license.php}
31
 * @see       ModelGenerator
32
 */
33
class GenerateForRelation extends RelationAwareCommand
34
{
35
    /**
36
     * configure
37
     *
38
     * @see Command
39
     */
40
    public function configure()
41
    {
42
        $this
43
            ->setName('pomm:generate:relation-all')
44
            ->setDescription('Generate structure, model and entity file for a given relation.')
45
            ;
46
        parent::configure();
47
        $this
48
            ->addOption(
49
                'force',
50
                null,
51
                InputOption::VALUE_NONE,
52
                'Force overwriting existing files.'
53
            )
54
            ->addOption(
55
                'psr4',
56
                null,
57
                InputOption::VALUE_NONE,
58
                'Use PSR4 structure.'
59
            )
60
        ;
61
    }
62
63
    /**
64
     * execute
65
     *
66
     * @see Command
67
     */
68
    protected function execute(InputInterface $input, OutputInterface $output)
69
    {
70
        parent::execute($input, $output);
71
72
        $session = $this->mustBeModelManagerSession($this->getSession());
73
74
        $this->updateOutput(
75
            $output,
76
            (new StructureGenerator(
77
                $session,
78
                $this->schema,
79
                $this->relation,
80
                $this->getPathFile($input->getArgument('config-name'), $this->relation, null, 'AutoStructure', $input->getOption('psr4')),
81
                $this->getNamespace($input->getArgument('config-name'), 'AutoStructure')
82
            ))->generate(new ParameterHolder(array_merge($input->getArguments(), $input->getOptions())))
83
        );
84
85
        $pathFile = $this->getPathFile($input->getArgument('config-name'), $this->relation, 'Model', '', $input->getOption('psr4'));
86 View Code Duplication
        if (!file_exists($pathFile) || $input->getOption('force')) {
87
            $this->updateOutput(
88
                $output,
89
                (new ModelGenerator(
90
                    $session,
91
                    $this->schema,
92
                    $this->relation,
93
                    $pathFile,
94
                    $this->getNamespace($input->getArgument('config-name'))
95
                ))->generate(new ParameterHolder(array_merge($input->getArguments(), $input->getOptions())))
96
            );
97
        } elseif ($output->isVerbose()) {
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Output\OutputInterface as the method isVerbose() does only exist in the following implementations of said interface: Symfony\Component\Console\Output\BufferedOutput, Symfony\Component\Console\Output\ConsoleOutput, Symfony\Component\Console\Output\NullOutput, Symfony\Component\Console\Output\Output, Symfony\Component\Console\Output\StreamOutput, Symfony\Component\Consol...ts\Fixtures\DummyOutput, Symfony\Component\Console\Tests\Output\TestOutput.

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...
98
            $this->writelnSkipFile($output, $pathFile, 'model');
99
        }
100
101
        $pathFile = $this->getPathFile($input->getArgument('config-name'), $this->relation, '', '', $input->getOption('psr4'));
102 View Code Duplication
        if (!file_exists($pathFile) || $input->getOption('force')) {
103
            $this->updateOutput(
104
                $output,
105
                (new EntityGenerator(
106
                    $session,
107
                    $this->schema,
108
                    $this->relation,
109
                    $pathFile,
110
                    $this->getNamespace($input->getArgument('config-name')),
111
                    $this->flexible_container
112
                ))->generate(new ParameterHolder(array_merge($input->getArguments(), $input->getOptions())))
113
            );
114
        } elseif ($output->isVerbose()) {
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Output\OutputInterface as the method isVerbose() does only exist in the following implementations of said interface: Symfony\Component\Console\Output\BufferedOutput, Symfony\Component\Console\Output\ConsoleOutput, Symfony\Component\Console\Output\NullOutput, Symfony\Component\Console\Output\Output, Symfony\Component\Console\Output\StreamOutput, Symfony\Component\Consol...ts\Fixtures\DummyOutput, Symfony\Component\Console\Tests\Output\TestOutput.

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...
115
            $this->writelnSkipFile($output, $pathFile, 'entity');
116
        }
117
    }
118
119
    /**
120
     * writelnSkipFile
121
     *
122
     * Write an informative message
123
     *
124
     * @access private
125
     * @param  OutputInterface $output
126
     * @param  string          $pathFile
127
     * @param  null|string     $file_type
128
     */
129
    private function writelnSkipFile(OutputInterface $output, $pathFile, $file_type = null)
130
    {
131
        $file_type = $file_type === null ? '' : sprintf("%s ", $file_type);
132
133
        $output->writeln(
134
            sprintf(
135
                " <fg=red>✗</fg=red>  <fg=blue>Preserving</fg=blue> existing %sfile <fg=yellow>'%s'</fg=yellow>.",
136
                $file_type,
137
                $pathFile
138
            )
139
        );
140
    }
141
}
142