GeneratorCommand::parseShortcutNotation()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
3
namespace Pgs\RestfonyBundle\Command;
4
5
use Symfony\Component\Console\Input\InputInterface;
6
use Symfony\Component\Console\Output\OutputInterface;
7
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
8
use Sensio\Bundle\GeneratorBundle\Command\GeneratorCommand as BaseGeneratorCommand;
9
use Sensio\Bundle\GeneratorBundle\Command\Validators;
10
use Doctrine\Bundle\DoctrineBundle\Mapping\DisconnectedMetadataFactory;
11
use Symfony\Component\Console\Question\ConfirmationQuestion;
12
13
/**
14
 * Here to modify skeleton dirs....need to figure out better way around that.
15
 * Some items borrowed from the GenerateDoctrineCommand and consolidated.
16
 */
17
abstract class GeneratorCommand extends BaseGeneratorCommand
18
{
19
    /**
20
     * @var string
21
     */
22
    protected $entity;
23
24
    /**
25
     * @param BundleInterface $bundle
26
     *
27
     * @return array
28
     */
29
    protected function getSkeletonDirs(BundleInterface $bundle = null)
30
    {
31
        $skeletonDirs = array();
32
33
        if (isset($bundle) && is_dir($dir = $bundle->getPath().'/Resources/PgsRestBundle/skeleton')) {
34
            $skeletonDirs[] = $dir;
35
        }
36
37
        if (is_dir($dir = $this->getContainer()->get('kernel')->getRootdir().'/Resources/PgsRestBundle/skeleton')) {
38
            $skeletonDirs[] = $dir;
39
        }
40
41
        $reflectionClass = new \ReflectionClass(get_class($this));
42
43
        $skeletonDirs[] = dirname($reflectionClass->getFileName()).'/../Resources/skeleton';
44
        $skeletonDirs[] = dirname($reflectionClass->getFileName()).'/../Resources';
45
46
        return $skeletonDirs;
47
    }
48
49
    /**
50
     * @return bool
51
     */
52
    public function isEnabled()
53
    {
54
        return class_exists('Doctrine\\Bundle\\DoctrineBundle\\DoctrineBundle');
55
    }
56
57
    /**
58
     * @param $shortcut
59
     *
60
     * @return array
61
     */
62
    protected function parseShortcutNotation($shortcut)
63
    {
64
        $entity = str_replace('/', '\\', $shortcut);
65
66
        if (false === $pos = strpos($entity, ':')) {
67
            throw new \InvalidArgumentException(sprintf(
68
                'The entity name must contain a : ("%s" given, expecting something like AcmeBlogBundle:Blog/Post)',
69
                $entity
70
            ));
71
        }
72
73
        return array(substr($entity, 0, $pos), substr($entity, $pos + 1));
74
    }
75
76
    /**
77
     * @param $entity
78
     *
79
     * @return array
80
     */
81
    protected function getEntityMetadata($entity)
82
    {
83
        $factory = new DisconnectedMetadataFactory($this->getContainer()->get('doctrine'));
84
85
        return $factory->getClassMetadata($entity)->getMetadata();
86
    }
87
88
    /**
89
     * The magic.
90
     *
91
     * @param InputInterface  $input
92
     * @param OutputInterface $output
93
     *
94
     * @return int|void
95
     */
96
    protected function execute(InputInterface $input, OutputInterface $output)
97
    {
98
        if ($input->isInteractive() && !$this->getQuestionHelper()->ask(
99
            $input,
100
            $output,
101
            new ConfirmationQuestion('Do you confirm generation of the '.$this->getFileTypeCreated().'? ', false)
0 ignored issues
show
Bug introduced by
The method getFileTypeCreated() does not seem to exist on object<Pgs\RestfonyBundl...mmand\GeneratorCommand>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
102
        )) {
103
            $output->writeln('<error>Command aborted</error>');
104
105
            return 1;
106
        }
107
108
        $this->entity = Validators::validateEntityName($input->getArgument('entity'));
109
        list($bundle, $entity) = $this->parseShortcutNotation($this->entity);
110
111
        $entityClass = $this->getContainer()->get('doctrine')->getAliasNamespace($bundle).'\\'.$entity;
112
        $metadata = $this->getEntityMetadata($entityClass);
113
        $bundle   = $this->getApplication()->getKernel()->getBundle($bundle);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Console\Application as the method getKernel() does only exist in the following sub-classes of Symfony\Component\Console\Application: Symfony\Bundle\FrameworkBundle\Console\Application. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
114
        $generator = $this->getGenerator();
115
        $generator->setFilesystem($this->getContainer()->get('filesystem'));
116
117
        try {
118
            $this->setOptions($input);
0 ignored issues
show
Bug introduced by
The method setOptions() does not seem to exist on object<Pgs\RestfonyBundl...mmand\GeneratorCommand>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
119
            $generator->generate($bundle, $entity, $metadata[0], $this->getOptions());
0 ignored issues
show
Bug introduced by
The method getOptions() does not seem to exist on object<Pgs\RestfonyBundl...mmand\GeneratorCommand>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
120
121
            $output->writeln(sprintf(
122
                '<info>The new %s %s file has been created under %s.</info>',
123
                $generator->getGeneratedName(),
124
                $this->getFileTypeCreated(),
0 ignored issues
show
Bug introduced by
The method getFileTypeCreated() does not seem to exist on object<Pgs\RestfonyBundl...mmand\GeneratorCommand>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
125
                $generator->getFilePath()
126
            ));
127
        } catch (\Exception $e) {
128
            $output->writeln("<error>".$this->getFailureMessage($e)."</error>");
0 ignored issues
show
Bug introduced by
The method getFailureMessage() does not seem to exist on object<Pgs\RestfonyBundl...mmand\GeneratorCommand>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
129
        }
130
    }
131
}
132