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 (#120)
by joseph
21:56
created

Container::getServices()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

360
            throw new DoctrineStaticMetaException('Exception getting service ' . $id, $e->/** @scrutinizer ignore-call */ getCode(), $e);
Loading history...
361
        }
362
    }
363
364
    /**
365
     * @param string $id
366
     * @SuppressWarnings(PHPMD.ShortVariable)
367
     *
368
     * @return bool|void
369
     */
370
    public function has($id)
371
    {
372
        return $this->container->has($id);
373
    }
374
}
375