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

Tools/Console/Command/GenerateHydratorsCommand.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\Tools\Console\MetadataFilter;
8
use InvalidArgumentException;
9
use Symfony\Component\Console;
10
use Symfony\Component\Console\Input\InputArgument;
11
use Symfony\Component\Console\Input\InputOption;
12
use const PHP_EOL;
13
use function assert;
14
use function count;
15
use function file_exists;
16
use function is_array;
17
use function is_dir;
18
use function is_writable;
19
use function mkdir;
20
use function realpath;
21
use function sprintf;
22
23
/**
24
 * Command to (re)generate the hydrator classes used by doctrine.
25
 */
26
class GenerateHydratorsCommand extends Console\Command\Command
27
{
28
    /**
29
     * @see Console\Command\Command
30
     */
31 View Code Duplication
    protected function configure()
32
    {
33
        $this
34
        ->setName('odm:generate:hydrators')
35
        ->setDescription('Generates hydrator classes for document classes.')
36
        ->setDefinition([
37
            new InputOption(
38
                'filter',
39
                null,
40
                InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
41
                'A string pattern used to match documents that should be processed.'
42
            ),
43
            new InputArgument(
44
                'dest-path',
45
                InputArgument::OPTIONAL,
46
                'The path to generate your hydrator classes. If none is provided, it will attempt to grab from configuration.'
47
            ),
48
        ])
49
        ->setHelp(<<<EOT
50
Generates hydrator classes for document classes.
51
EOT
52
        );
53
    }
54
55
    /**
56
     * @see Console\Command\Command
57
     */
58
    protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
59
    {
60
        $filter = $input->getOption('filter');
61
        assert(is_array($filter));
62
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
        $metadatas = $dm->getMetadataFactory()->getAllMetadata();
66
        $metadatas = MetadataFilter::filter($metadatas, $filter);
67
        $destPath  = $input->getArgument('dest-path');
68
69
        // Process destination directory
70
        if ($destPath === null) {
71
            $destPath = $dm->getConfiguration()->getHydratorDir();
72
        }
73
74
        if (! is_dir($destPath)) {
75
            mkdir($destPath, 0775, true);
76
        }
77
78
        $destPath = realpath($destPath);
79
        assert($destPath !== false);
80
81 View Code Duplication
        if (! file_exists($destPath)) {
82
            throw new InvalidArgumentException(
83
                sprintf("Hydrators destination directory '<info>%s</info>' does not exist.", $destPath)
84
            );
85
        } elseif (! is_writable($destPath)) {
86
            throw new InvalidArgumentException(
87
                sprintf("Hydrators destination directory '<info>%s</info>' does not have write permissions.", $destPath)
88
            );
89
        }
90
91 View Code Duplication
        if (count($metadatas)) {
92
            foreach ($metadatas as $metadata) {
93
                $output->write(
94
                    sprintf('Processing document "<info>%s</info>"', $metadata->name) . PHP_EOL
95
                );
96
            }
97
98
            // Generating Hydrators
99
            $dm->getHydratorFactory()->generateHydratorClasses($metadatas, $destPath);
100
101
            // Outputting information message
102
            $output->write(PHP_EOL . sprintf('Hydrator classes generated to "<info>%s</INFO>"', $destPath) . PHP_EOL);
103
        } else {
104
            $output->write('No Metadata Classes to process.' . PHP_EOL);
105
        }
106
    }
107
}
108