Completed
Push — master ( 7b9f4b...1cd743 )
by Andreas
13s queued 10s
created

Tools/Console/Command/GenerateProxiesCommand.php (1 issue)

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
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Tools\Console\Command;
6
7
use Doctrine\ODM\MongoDB\ConfigurationException;
8
use Doctrine\ODM\MongoDB\DocumentManager;
9
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
10
use Doctrine\ODM\MongoDB\Tools\Console\MetadataFilter;
11
use InvalidArgumentException;
12
use Symfony\Component\Console;
13
use Symfony\Component\Console\Input\InputOption;
14
use const PHP_EOL;
15
use function array_filter;
16
use function assert;
17
use function count;
18
use function file_exists;
19
use function is_array;
20
use function is_dir;
21
use function is_string;
22
use function is_writable;
23
use function mkdir;
24
use function realpath;
25
use function sprintf;
26
27
/**
28
 * Command to (re)generate the proxy classes used by doctrine.
29
 */
30
class GenerateProxiesCommand extends Console\Command\Command
31
{
32
    /**
33
     * @see Console\Command\Command
34
     */
35
    protected function configure()
36
    {
37
        $this
38
        ->setName('odm:generate:proxies')
39
        ->setDescription('Generates proxy classes for document classes.')
40
        ->setDefinition([
41
            new InputOption(
42
                'filter',
43
                null,
44
                InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
45
                'A string pattern used to match documents that should be processed.'
46
            ),
47
        ])
48
        ->setHelp(<<<EOT
49
Generates proxy classes for document classes.
50
EOT
51
        );
52
    }
53
54
    /**
55
     * @see Console\Command\Command
56
     */
57
    protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
58
    {
59
        $filter = $input->getOption('filter');
60
        assert(is_array($filter));
61
62
        /** @var DocumentManager $dm */
63
        $dm = $this->getHelper('documentManager')->getDocumentManager();
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method getDocumentManager() does only exist in the following implementations of said interface: Doctrine\ODM\MongoDB\Too...r\DocumentManagerHelper.

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...
64
65
        /** @var ClassMetadata[] $metadatas */
66
        $metadatas = array_filter($dm->getMetadataFactory()->getAllMetadata(), static function (ClassMetadata $classMetadata) : bool {
67
            return ! $classMetadata->isEmbeddedDocument && ! $classMetadata->isMappedSuperclass && ! $classMetadata->isQueryResultDocument;
68
        });
69
        $metadatas = MetadataFilter::filter($metadatas, $filter);
70
        $destPath  = $dm->getConfiguration()->getProxyDir();
71
72
        if (! is_string($destPath)) {
73
            throw ConfigurationException::proxyDirMissing();
74
        }
75
76
        if (! is_dir($destPath)) {
77
            mkdir($destPath, 0775, true);
78
        }
79
80
        $destPath = realpath($destPath);
81
        assert($destPath !== false);
82
83 View Code Duplication
        if (! file_exists($destPath)) {
84
            throw new InvalidArgumentException(
85
                sprintf("Proxies destination directory '<info>%s</info>' does not exist.", $destPath)
86
            );
87
        } elseif (! is_writable($destPath)) {
88
            throw new InvalidArgumentException(
89
                sprintf("Proxies destination directory '<info>%s</info>' does not have write permissions.", $destPath)
90
            );
91
        }
92
93 View Code Duplication
        if (count($metadatas)) {
94
            foreach ($metadatas as $metadata) {
95
                $output->write(
96
                    sprintf('Processing document "<info>%s</info>"', $metadata->name) . PHP_EOL
97
                );
98
            }
99
100
            // Generating Proxies
101
            $dm->getProxyFactory()->generateProxyClasses($metadatas);
102
103
            // Outputting information message
104
            $output->write(PHP_EOL . sprintf('Proxy classes generated to "<info>%s</INFO>"', $destPath) . PHP_EOL);
105
        } else {
106
            $output->write('No Metadata Classes to process.' . PHP_EOL);
107
        }
108
    }
109
}
110