DoctrineBundle   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 16
dl 0
loc 119
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A build() 0 17 2
B boot() 0 47 6
B shutdown() 0 31 8
A registerCommands() 0 3 1
1
<?php
2
3
namespace Doctrine\Bundle\DoctrineBundle;
4
5
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\CacheSchemaSubscriberPass;
6
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DbalSchemaFilterPass;
7
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\EntityListenerPass;
8
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass;
9
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\WellKnownSchemaFilterPass;
10
use Doctrine\Common\Util\ClassUtils;
11
use Doctrine\ORM\EntityManager;
12
use Doctrine\ORM\Proxy\Autoloader;
13
use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\DoctrineValidationPass;
14
use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass;
15
use Symfony\Bridge\Doctrine\DependencyInjection\Security\UserProvider\EntityFactory;
16
use Symfony\Component\Console\Application;
17
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
18
use Symfony\Component\DependencyInjection\ContainerBuilder;
19
use Symfony\Component\HttpKernel\Bundle\Bundle;
20
21
class DoctrineBundle extends Bundle
22
{
23
    /** @var callable|null */
24
    private $autoloader;
25
26
    /**
27
     * {@inheritDoc}
28
     */
29
    public function build(ContainerBuilder $container)
30
    {
31
        parent::build($container);
32
33
        $container->addCompilerPass(new RegisterEventListenersAndSubscribersPass('doctrine.connections', 'doctrine.dbal.%s_connection.event_manager', 'doctrine'), PassConfig::TYPE_BEFORE_OPTIMIZATION);
34
35
        if ($container->hasExtension('security')) {
36
            $container->getExtension('security')->addUserProviderFactory(new EntityFactory('entity', 'doctrine.orm.security.user.provider'));
0 ignored issues
show
Bug introduced by
The method addUserProviderFactory() does not seem to exist on object<Symfony\Component...ion\ExtensionInterface>.

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...
37
        }
38
39
        $container->addCompilerPass(new DoctrineValidationPass('orm'));
40
        $container->addCompilerPass(new EntityListenerPass());
41
        $container->addCompilerPass(new ServiceRepositoryCompilerPass());
42
        $container->addCompilerPass(new WellKnownSchemaFilterPass());
43
        $container->addCompilerPass(new DbalSchemaFilterPass());
44
        $container->addCompilerPass(new CacheSchemaSubscriberPass(), PassConfig::TYPE_OPTIMIZE, -10);
45
    }
46
47
    /**
48
     * {@inheritDoc}
49
     */
50
    public function boot()
51
    {
52
        // Register an autoloader for proxies to avoid issues when unserializing them
53
        // when the ORM is used.
54
        if (! $this->container->hasParameter('doctrine.orm.proxy_namespace')) {
55
            return;
56
        }
57
58
        $namespace      = $this->container->getParameter('doctrine.orm.proxy_namespace');
59
        $dir            = $this->container->getParameter('doctrine.orm.proxy_dir');
60
        $proxyGenerator = null;
61
62
        if ($this->container->getParameter('doctrine.orm.auto_generate_proxy_classes')) {
63
            // See https://github.com/symfony/symfony/pull/3419 for usage of references
64
            $container = &$this->container;
65
66
            $proxyGenerator = static function ($proxyDir, $proxyNamespace, $class) use (&$container) {
67
                $originalClassName = ClassUtils::getRealClass($class);
68
                /** @var Registry $registry */
69
                $registry = $container->get('doctrine');
70
71
                // Tries to auto-generate the proxy file
72
                /** @var EntityManager $em */
73
                foreach ($registry->getManagers() as $em) {
74
                    if (! $em->getConfiguration()->getAutoGenerateProxyClasses()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectManager as the method getConfiguration() does only exist in the following implementations of said interface: Doctrine\ORM\Decorator\EntityManagerDecorator, Doctrine\ORM\EntityManager.

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...
75
                        continue;
76
                    }
77
78
                    $metadataFactory = $em->getMetadataFactory();
79
80
                    if ($metadataFactory->isTransient($originalClassName)) {
81
                        continue;
82
                    }
83
84
                    $classMetadata = $metadataFactory->getMetadataFor($originalClassName);
85
86
                    $em->getProxyFactory()->generateProxyClasses([$classMetadata]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectManager as the method getProxyFactory() does only exist in the following implementations of said interface: Doctrine\ORM\Decorator\EntityManagerDecorator, Doctrine\ORM\EntityManager.

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...
87
88
                    clearstatcache(true, Autoloader::resolveFile($proxyDir, $proxyNamespace, $class));
89
90
                    break;
91
                }
92
            };
93
        }
94
95
        $this->autoloader = Autoloader::register($dir, $namespace, $proxyGenerator);
96
    }
97
98
    /**
99
     * {@inheritDoc}
100
     */
101
    public function shutdown()
102
    {
103
        if ($this->autoloader !== null) {
104
            spl_autoload_unregister($this->autoloader);
105
            $this->autoloader = null;
106
        }
107
108
        // Clear all entity managers to clear references to entities for GC
109
        if ($this->container->hasParameter('doctrine.entity_managers')) {
110
            foreach ($this->container->getParameter('doctrine.entity_managers') as $id) {
111
                if (! $this->container->initialized($id)) {
112
                    continue;
113
                }
114
115
                $this->container->get($id)->clear();
116
            }
117
        }
118
119
        // Close all connections to avoid reaching too many connections in the process when booting again later (tests)
120
        if (! $this->container->hasParameter('doctrine.connections')) {
121
            return;
122
        }
123
124
        foreach ($this->container->getParameter('doctrine.connections') as $id) {
125
            if (! $this->container->initialized($id)) {
126
                continue;
127
            }
128
129
            $this->container->get($id)->close();
130
        }
131
    }
132
133
    /**
134
     * {@inheritDoc}
135
     */
136
    public function registerCommands(Application $application)
137
    {
138
    }
139
}
140