GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#95)
by Ross
13:04 queued 10:08
created

Container   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 288
Duplicated Lines 0 %

Test Coverage

Coverage 79.73%

Importance

Changes 0
Metric Value
wmc 19
eloc 100
dl 0
loc 288
ccs 59
cts 74
cp 0.7973
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A setUseCache() 0 5 1
A autoWireServices() 0 5 2
A buildSymfonyContainer() 0 22 4
A autoWireConfig() 0 4 1
A autoWireCache() 0 14 2
A configVars() 0 8 1
A addConfiguration() 0 7 1
A setContainer() 0 5 1
A getServices() 0 3 1
A autoWireEntityManager() 0 8 1
A has() 0 3 1
A setupEntityValidator() 0 9 1
A get() 0 6 2
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta;
4
5
use Doctrine\Common\Cache\ArrayCache;
6
use Doctrine\Common\Cache\Cache;
7
use Doctrine\ORM\EntityManager;
8
use Doctrine\ORM\EntityManagerInterface;
9
use Doctrine\ORM\Tools\SchemaTool;
10
use Doctrine\ORM\Tools\SchemaValidator;
11
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\CodeHelper;
12
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\GenerateEmbeddableFromArchetypeCommand;
13
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\GenerateEntityCommand;
14
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\GenerateFieldCommand;
15
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\GenerateRelationsCommand;
16
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\RemoveUnusedRelationsCommand;
17
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\SetEmbeddableCommand;
18
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\SetFieldCommand;
19
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\SetRelationCommand;
20
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Embeddable\ArchetypeEmbeddableGenerator;
21
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Embeddable\EntityEmbeddableSetter;
22
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\EntityGenerator;
23
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\EntityFieldSetter;
24
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\FieldGenerator;
25
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\StandardLibraryTestGenerator;
26
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FileCreationTransaction;
27
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FindAndReplaceHelper;
28
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\RelationsGenerator;
29
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
30
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PathHelper;
31
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\TypeHelper;
32
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\UnusedRelationsRemover;
33
use EdmondsCommerce\DoctrineStaticMeta\Entity\Factory\EntityFactory;
34
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\Validation\EntityValidatorInterface;
35
use EdmondsCommerce\DoctrineStaticMeta\Entity\Savers\EntitySaver;
36
use EdmondsCommerce\DoctrineStaticMeta\Entity\Savers\EntitySaverFactory;
37
use EdmondsCommerce\DoctrineStaticMeta\Entity\Validation\EntityValidator;
38
use EdmondsCommerce\DoctrineStaticMeta\Entity\Validation\EntityValidatorFactory;
39
use EdmondsCommerce\DoctrineStaticMeta\EntityManager\EntityManagerFactory;
40
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
41
use EdmondsCommerce\DoctrineStaticMeta\Schema\Database;
42
use EdmondsCommerce\DoctrineStaticMeta\Schema\Schema;
43
use Psr\Container\ContainerExceptionInterface;
44
use Psr\Container\ContainerInterface;
45
use Psr\Container\NotFoundExceptionInterface;
46
use Symfony\Component\DependencyInjection\ContainerBuilder;
47
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
48
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
49
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
50
use Symfony\Component\DependencyInjection\Reference;
51
use Symfony\Component\Filesystem\Filesystem;
52
use Symfony\Component\Validator\Mapping\Cache\DoctrineCache;
53
54
/**
55
 * Class Container
56
 *
57
 * @package EdmondsCommerce\DoctrineStaticMeta
58
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
59
 */
60
class Container implements ContainerInterface
61
{
62
    /**
63
     * This is the list of services managed by this container
64
     *
65
     * This list is used to also generate a PHPStorm meta data file which assists with dynamic type hinting when using
66
     * the container as a service locator
67
     *
68
     * @see ./../../.phpstorm.meta.php/container.meta.php
69
     */
70
    public const SERVICES = [
71
        ArchetypeEmbeddableGenerator::class,
72
        CodeHelper::class,
73
        Config::class,
74
        Database::class,
75
        DoctrineCache::class,
76
        EntityEmbeddableSetter::class,
77
        EntityFactory::class,
78
        EntityFieldSetter::class,
79
        EntityGenerator::class,
80
        EntityManagerInterface::class,
81
        EntityManagerFactory::class,
82
        EntitySaver::class,
83
        EntitySaverFactory::class,
84
        EntityValidator::class,
85
        EntityValidatorFactory::class,
86
        FieldGenerator::class,
87
        FileCreationTransaction::class,
88
        Filesystem::class,
89
        FindAndReplaceHelper::class,
90
        GenerateEmbeddableFromArchetypeCommand::class,
91
        GenerateEntityCommand::class,
92
        GenerateFieldCommand::class,
93
        GenerateRelationsCommand::class,
94
        NamespaceHelper::class,
95
        PathHelper::class,
96
        RelationsGenerator::class,
97
        RelationsGenerator::class,
98
        RemoveUnusedRelationsCommand::class,
99
        Schema::class,
100
        Schema::class,
101
        SchemaTool::class,
102
        SchemaValidator::class,
103
        SetEmbeddableCommand::class,
104
        SetFieldCommand::class,
105
        SetRelationCommand::class,
106
        StandardLibraryTestGenerator::class,
107
        TypeHelper::class,
108
        UnusedRelationsRemover::class,
109
    ];
110
111
    /**
112
     * The directory that container cache files will be stored
113
     */
114
    public const CACHE_PATH = __DIR__ . '/../cache/';
115
116
    public const SYMFONY_CACHE_PATH = self::CACHE_PATH . '/container.symfony.php';
117
118
    /**
119
     * @var bool
120
     */
121
    private $useCache = false;
122
123
    /**
124
     * @var ContainerInterface
125
     */
126
    private $container;
127
128
    /**
129
     * @param bool $useCache
130
     *
131
     * @return Container
132
     */
133
    public function setUseCache(bool $useCache): Container
134
    {
135
        $this->useCache = $useCache;
136
137
        return $this;
138
    }
139
140
    /**
141
     * @param array $server - normally you would pass in $_SERVER
142
     *
143
     * @throws DoctrineStaticMetaException
144
     */
145 145
    public function buildSymfonyContainer(array $server): void
146
    {
147 145
        if (true === $this->useCache && file_exists(self::SYMFONY_CACHE_PATH)) {
148
            /** @noinspection PhpIncludeInspection */
149
            require self::SYMFONY_CACHE_PATH;
150
            $this->setContainer(new \ProjectServiceContainer());
151
152
            return;
153
        }
154
155
        try {
156 145
            $container = new ContainerBuilder();
157 145
            $this->addConfiguration($container, $server);
158 145
            $container->compile();
159 145
            $this->setContainer($container);
160 145
            $dumper = new PhpDumper($container);
161 145
            file_put_contents(self::SYMFONY_CACHE_PATH, $dumper->dump());
162
        } catch (ServiceNotFoundException | InvalidArgumentException $e) {
163
            throw new DoctrineStaticMetaException(
164
                'Exception building the container: ' . $e->getMessage(),
165
                $e->getCode(),
166
                $e
167
            );
168
        }
169 145
    }
170
171
    /**
172
     * Set a container instance
173
     *
174
     * @param ContainerInterface $container
175
     *
176
     * @return $this
177
     */
178 145
    public function setContainer(ContainerInterface $container): self
179
    {
180 145
        $this->container = $container;
181
182 145
        return $this;
183
    }
184
185
    /**
186
     * Build all the definitions, alias and other configuration for this container. Each of these steps need to be
187
     * carried out to allow the everything to work, however you may wish to change individual bits. Therefore this
188
     * method has been made final, but the individual methods can be overwritten if you extend off the class
189
     *
190
     * @param ContainerBuilder $container
191
     * @param array            $server
192
     *
193
     * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
194
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
195
     */
196 145
    final public function addConfiguration(ContainerBuilder $container, array $server): void
197
    {
198 145
        $this->autoWireServices($container);
199 145
        $this->autoWireCache($container, $server);
200 145
        $this->autoWireConfig($container, $server);
201 145
        $this->autoWireEntityManager($container);
202 145
        $this->setupEntityValidator($container);
203 145
    }
204
205
    /**
206
     * This takes every class from the getServices method, auto wires them and marks them as public. You may wish to
207
     * override this if you want to mark certain classes as private
208
     *
209
     * @param ContainerBuilder $container
210
     */
211 145
    public function autoWireServices(ContainerBuilder $container): void
212
    {
213 145
        $services = $this->getServices();
214 145
        foreach ($services as $class) {
215 145
            $container->autowire($class, $class)->setPublic(true);
216
        }
217 145
    }
218
219
    /**
220
     * This is a simple wrapper around the class constants. You can use this to add, remove, or replace individual
221
     * services that will be auto wired
222
     *
223
     * @return array
224
     */
225 145
    public function getServices(): array
226
    {
227 145
        return self::SERVICES;
228
    }
229
230
    /**
231
     * This is used to auto wire the doctrine cache. If we are in dev mode then this will always use the Array Cache,
232
     * if not then the cache will be set to what is in the $server array. Override this method if you wish to use
233
     * different logic to handle caching
234
     *
235
     * @param ContainerBuilder $container
236
     * @param array            $server
237
     */
238 145
    public function autoWireCache(ContainerBuilder $container, array $server): void
239
    {
240 145
        $cacheDriver = $server[Config::PARAM_DOCTRINE_CACHE_DRIVER] ?? Config::DEFAULT_DOCTRINE_CACHE_DRIVER;
241 145
        $container->autowire($cacheDriver);
242
        /**
243
         * Which Cache Driver is used for the Cache Inteface?
244
         *
245
         * If Dev mode, we always use the Array Cache
246
         *
247
         * Otherwise, we use the Configured Cache driver (which defaults to Array Cache)
248
         */
249 145
        $cache = ($server[Config::PARAM_DEVMODE] ?? false) ? ArrayCache::class : $cacheDriver;
250 145
        $container->setAlias(Cache::class, $cache);
251 145
        $container->getDefinition(DoctrineCache::class)->addArgument(new Reference($cacheDriver));
252 145
    }
253
254
    /**
255
     * This is used to auto wire the config interface. It sets the $server param as a constructor argument and then
256
     * sets the concrete class as the implementation for the Interface. Override this if you wish to use different
257
     * logic for where the config comes from
258
     *
259
     * @param ContainerBuilder $container
260
     * @param array            $server
261
     */
262 145
    public function autoWireConfig(ContainerBuilder $container, array $server): void
263
    {
264 145
        $container->getDefinition(Config::class)->setArgument('$server', $this->configVars($server));
265 145
        $container->setAlias(ConfigInterface::class, Config::class);
266 145
    }
267
268
    /**
269
     * Take the $server array, normally a copy of $_SERVER, and pull out just the bits required by config
270
     *
271
     * @param array $server
272
     *
273
     * @return array
274
     */
275 145
    protected function configVars(array $server): array
276
    {
277 145
        $return = array_intersect_key(
278 145
            $server,
279 145
            array_flip(ConfigInterface::PARAMS)
280
        );
281
282 145
        return $return;
283
    }
284
285
    /**
286
     * This is used to auto wire the entity manager. It first adds the DSM factory as the factory for the class, and
287
     * sets the Entity Manager as the implementation of the interface. Overrider this if you want to use your own
288
     * factory to create and configure the entity manager
289
     *
290
     * @param ContainerBuilder $container
291
     */
292 145
    public function autoWireEntityManager(ContainerBuilder $container): void
293
    {
294 145
        $container->getDefinition(EntityManagerInterface::class)
295 145
                  ->addArgument(new Reference(Config::class))
296 145
                  ->setFactory(
297
                      [
298 145
                          new Reference(EntityManagerFactory::class),
299 145
                          'getEntityManager',
300
                      ]
301
                  );
302 145
    }
303
304
    /**
305
     * This is used to auto wire and set the factory for the entity validator. Override this if you wish to use you own
306
     * validator
307
     *
308
     * @param ContainerBuilder $container
309
     */
310 145
    public function setupEntityValidator(ContainerBuilder $container): void
311
    {
312 145
        $container->setAlias(EntityValidatorInterface::class, EntityValidator::class);
313 145
        $container->getDefinition(EntityValidator::class)
314 145
                  ->addArgument(new Reference(Cache::class))
315 145
                  ->setFactory(
316
                      [
317 145
                          new Reference(EntityValidatorFactory::class),
318 145
                          'getEntityValidator',
319
                      ]
320
                  );
321 145
    }
322
323
    /**
324
     * @param string $id
325
     *
326
     * @return mixed
327
     * @SuppressWarnings(PHPMD.ShortVariable)
328
     * @throws DoctrineStaticMetaException
329
     */
330 141
    public function get($id)
331
    {
332
        try {
333 141
            return $this->container->get($id);
334
        } catch (ContainerExceptionInterface | NotFoundExceptionInterface $e) {
335
            throw new DoctrineStaticMetaException('Exception getting service ' . $id, $e->getCode(), $e);
0 ignored issues
show
Bug introduced by
The method getCode() does not exist on Psr\Container\ContainerExceptionInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Psr\Container\NotFoundExceptionInterface or Symfony\Component\Depend...tion\ExceptionInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

335
            throw new DoctrineStaticMetaException('Exception getting service ' . $id, $e->/** @scrutinizer ignore-call */ getCode(), $e);
Loading history...
336
        }
337
    }
338
339
    /**
340
     * @param string $id
341
     * @SuppressWarnings(PHPMD.ShortVariable)
342
     *
343
     * @return bool|void
344
     */
345
    public function has($id)
346
    {
347
        return $this->container->has($id);
348
    }
349
}
350