‪TYPO3CMS  ‪main
FailsafeContainer.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Container\ContainerInterface;
21 
25 class ‪FailsafeContainer implements ContainerInterface
26 {
30  private ‪$entries = [];
31 
35  private ‪$factories = [];
36 
45  public function ‪__construct(iterable $providers = [], array ‪$entries = [])
46  {
47  $this->entries = ‪$entries;
48 
49  ‪$factories = [];
50  foreach ($providers as $provider) {
52  ‪$factories = $provider->getFactories() + ‪$factories;
53  foreach ($provider->getExtensions() as $id => $extension) {
54  // Decorate a previously defined extension or if that is not available,
55  // create a lazy lookup to a factory from the list of vanilla factories.
56  // Lazy because we currently can not know whether a factory will only
57  // become available due to a subsequent provider.
58  $innerFactory = $this->factories[$id] ?? static function (ContainerInterface $c) use (&‪$factories, $id) {
59  return isset(‪$factories[$id]) ? ‪$factories[$id]($c) : null;
60  };
61 
62  $this->factories[$id] = static function (ContainerInterface $container) use ($extension, $innerFactory) {
63  $previous = $innerFactory($container);
64  return $extension($container, $previous);
65  };
66  }
67  }
68 
69  // Add factories to the list of factories for services that were not extended.
70  // (i.e those that have not been specified in getExtensions)
71  $this->factories += ‪$factories;
72  }
73 
74  public function ‪has(string $id): bool
75  {
76  return array_key_exists($id, $this->entries) || array_key_exists($id, $this->factories);
77  }
78 
82  private function ‪create(string $id)
83  {
84  $factory = $this->factories[$id] ?? null;
85 
86  if ((bool)$factory) {
87  // Remove factory as it is no longer required.
88  // Set factory to false to be able to detect
89  // cyclic dependency loops.
90  $this->factories[$id] = false;
91 
92  return $this->entries[$id] = $factory($this);
93  }
94  if (array_key_exists($id, $this->entries)) {
95  // This condition is triggered in the unlikely case that the entry is null
96  // Note: That is because the coalesce operator used in get() can not handle that
97  return $this->entries[$id];
98  }
99  if ($factory === null) {
100  throw new NotFoundException('Container entry "' . $id . '" is not available.', 1519978105);
101  }
102  // if ($factory === false)
103  throw new ContainerException('Container entry "' . $id . '" is part of a cyclic dependency chain.', 1520175002);
104  }
105 
109  public function get(string $id)
110  {
111  return $this->entries[$id] ?? $this->‪create($id);
112  }
113 }
‪TYPO3\CMS\Core\DependencyInjection\ContainerException
Definition: ContainerException.php:26
‪TYPO3\CMS\Core\DependencyInjection\FailsafeContainer\$entries
‪array $entries
Definition: FailsafeContainer.php:29
‪TYPO3\CMS\Core\DependencyInjection\FailsafeContainer\create
‪mixed create(string $id)
Definition: FailsafeContainer.php:80
‪TYPO3\CMS\Core\DependencyInjection\FailsafeContainer
Definition: FailsafeContainer.php:26
‪TYPO3\CMS\Core\DependencyInjection\FailsafeContainer\has
‪has(string $id)
Definition: FailsafeContainer.php:72
‪TYPO3\CMS\Core\DependencyInjection
Definition: AutowireInjectMethodsPass.php:18
‪TYPO3\CMS\Core\DependencyInjection\FailsafeContainer\$factories
‪array $factories
Definition: FailsafeContainer.php:33
‪TYPO3\CMS\Core\DependencyInjection\FailsafeContainer\__construct
‪__construct(iterable $providers=[], array $entries=[])
Definition: FailsafeContainer.php:43
‪TYPO3\CMS\Core\DependencyInjection\NotFoundException
Definition: NotFoundException.php:26