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 (#100)
by joseph
18:26
created

Container::defineEntityManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

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

353
            throw new DoctrineStaticMetaException('Exception getting service ' . $id, $e->/** @scrutinizer ignore-call */ getCode(), $e);
Loading history...
354
        }
355
    }
356
357
    /**
358
     * @param string $id
359
     * @SuppressWarnings(PHPMD.ShortVariable)
360
     *
361
     * @return bool|void
362
     */
363
    public function has($id)
364
    {
365
        return $this->container->has($id);
366
    }
367
}
368