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 (#74)
by Ross
11:11
created

Container::setUseCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
ccs 0
cts 3
cp 0
cc 1
nc 1
nop 1
crap 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
        EntityManager::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
    /**
142
     * Set a container instance
143
     *
144
     * @param ContainerInterface $container
145
     *
146
     * @return $this
147
     */
148 142
    public function setContainer(ContainerInterface $container): self
149
    {
150 142
        $this->container = $container;
151
152 142
        return $this;
153
    }
154
155
    /**
156
     * Take the $server array, normally a copy of $_SERVER, and pull out just the bits required by config
157
     *
158
     * @param array $server
159
     *
160
     * @return array
161
     */
162 142
    protected function configVars(array $server): array
163
    {
164 142
        $return = array_intersect_key(
165 142
            $server,
166 142
            array_flip(ConfigInterface::PARAMS)
167
        );
168
169 142
        return $return;
170
    }
171
172
    /**
173
     * @param array $server - normally you would pass in $_SERVER
174
     *
175
     * @throws DoctrineStaticMetaException
176
     */
177 142
    public function buildSymfonyContainer(array $server): void
178
    {
179 142
        if (true === $this->useCache && file_exists(self::SYMFONY_CACHE_PATH)) {
180
            /** @noinspection PhpIncludeInspection */
181
            require self::SYMFONY_CACHE_PATH;
182
            $this->setContainer(new \ProjectServiceContainer());
183
184
            return;
185
        }
186
187
        try {
188 142
            $container = new ContainerBuilder();
189 142
            $this->addConfiguration($container, $server);
190 142
            $container->compile();
191 142
            $this->setContainer($container);
192 142
            $dumper = new PhpDumper($container);
193 142
            file_put_contents(self::SYMFONY_CACHE_PATH, $dumper->dump());
194
        } catch (ServiceNotFoundException|InvalidArgumentException $e) {
195
            throw new DoctrineStaticMetaException(
196
                'Exception building the container: ' . $e->getMessage(),
197
                $e->getCode(),
198
                $e
199
            );
200
        }
201 142
    }
202
203
    /**
204
     * Build all the definitions, alias and other configuration for this container. Each of these steps need to be
205
     * carried out to allow the everything to work, however you may wish to change individual bits. Therefore this
206
     * method has been made final, but the individual methods can be overwritten if you extend off the class
207
     *
208
     * @param ContainerBuilder $container
209
     * @param array            $server
210
     *
211
     * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
212
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
213
     */
214 142
    final public function addConfiguration(ContainerBuilder $container, array $server): void
215
    {
216 142
        $this->autoWireServices($container);
217 142
        $this->autoWireCache($container, $server);
218 142
        $this->autoWireConfig($container, $server);
219 142
        $this->autoWireEntityManager($container);
220 142
        $this->setupEntityValidator($container);
221 142
    }
222
223
    /**
224
     * This is a simple wrapper around the class constants. You can use this to add, remove, or replace individual
225
     * services that will be auto wired
226
     *
227
     * @return array
228
     */
229 142
    public function getServices(): array
230
    {
231 142
        return self::SERVICES;
232
    }
233
234
    /**
235
     * This takes every class from the getServices method, auto wires them and marks them as public. You may wish to
236
     * override this if you want to mark certain classes as private
237
     *
238
     * @param ContainerBuilder $container
239
     */
240 142
    public function autoWireServices(ContainerBuilder $container): void
241
    {
242 142
        $services = $this->getServices();
243 142
        foreach ($services as $class) {
244 142
            $container->autowire($class, $class)->setPublic(true);
245
        }
246 142
    }
247
248
    /**
249
     * This is used to auto wire the doctrine cache. If we are in dev mode then this will always use the Array Cache,
250
     * if not then the cache will be set to what is in the $server array. Override this method if you wish to use
251
     * different logic to handle caching
252
     *
253
     * @param ContainerBuilder $container
254
     * @param array            $server
255
     */
256 142
    public function autoWireCache(ContainerBuilder $container, array $server): void
257
    {
258 142
        $cacheDriver = $server[Config::PARAM_DOCTRINE_CACHE_DRIVER] ?? Config::DEFAULT_DOCTRINE_CACHE_DRIVER;
259 142
        $container->autowire($cacheDriver);
260
        /**
261
         * Which Cache Driver is used for the Cache Inteface?
262
         *
263
         * If Dev mode, we always use the Array Cache
264
         *
265
         * Otherwise, we use the Configured Cache driver (which defaults to Array Cache)
266
         */
267 142
        $cache = ($server[Config::PARAM_DEVMODE] ?? false) ? ArrayCache::class : $cacheDriver;
268 142
        $container->setAlias(Cache::class, $cache);
269 142
        $container->getDefinition(DoctrineCache::class)->addArgument(new Reference($cacheDriver));
270 142
    }
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 $container
278
     * @param array            $server
279
     */
280 142
    public function autoWireConfig(ContainerBuilder $container, array $server): void
281
    {
282 142
        $container->getDefinition(Config::class)->setArgument('$server', $this->configVars($server));
283 142
        $container->setAlias(ConfigInterface::class, Config::class);
284 142
    }
285
286
    /**
287
     * This is used to auto wire the entity manager. It first adds the DSM factory as the factory for the class, and
288
     * sets the Entity Manager as the implementation of the interface. Overrider this if you want to use your own
289
     * factory to create and configure the entity manager
290
     *
291
     * @param ContainerBuilder $container
292
     */
293 142
    public function autoWireEntityManager(ContainerBuilder $container): void
294
    {
295 142
        $container->getDefinition(EntityManager::class)
296 142
                  ->addArgument(new Reference(Config::class))
297 142
                  ->setFactory(
298
                      [
299 142
                          new Reference(EntityManagerFactory::class),
300 142
                          'getEntityManager',
301
                      ]
302
                  );
303
304
305 142
        $container->setAlias(EntityManagerInterface::class, EntityManager::class)->setPublic(true);
306 142
    }
307
308
    /**
309
     * This is used to auto wire and set the factory for the entity validator. Override this if you wish to use you own
310
     * validator
311
     *
312
     * @param ContainerBuilder $container
313
     */
314 142
    public function setupEntityValidator(ContainerBuilder $container): void
315
    {
316 142
        $container->setAlias(EntityValidatorInterface::class, EntityValidator::class);
317 142
        $container->getDefinition(EntityValidator::class)
318 142
                  ->addArgument(new Reference(Cache::class))
319 142
                  ->setFactory(
320
                      [
321 142
                          new Reference(EntityValidatorFactory::class),
322 142
                          'getEntityValidator',
323
                      ]
324
                  );
325 142
    }
326
327
    /**
328
     * @param string $id
329
     *
330
     * @return mixed
331
     * @SuppressWarnings(PHPMD.ShortVariable)
332
     * @throws DoctrineStaticMetaException
333
     */
334 138
    public function get($id)
335
    {
336
        try {
337 138
            return $this->container->get($id);
338
        } catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) {
339
            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

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