Gacela::runPlugins()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 13
ccs 0
cts 0
cp 0
crap 12
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework;
6
7
use Closure;
8
use Gacela\Framework\Bootstrap\GacelaConfig;
9
use Gacela\Framework\Bootstrap\SetupGacela;
10
use Gacela\Framework\Bootstrap\SetupGacelaInterface;
11
use Gacela\Framework\ClassResolver\AbstractClassResolver;
12
use Gacela\Framework\ClassResolver\Cache\GacelaFileCache;
13
use Gacela\Framework\ClassResolver\Cache\InMemoryCache;
14
use Gacela\Framework\ClassResolver\ClassResolverCache;
15
use Gacela\Framework\ClassResolver\GlobalInstance\AnonymousGlobal;
16
use Gacela\Framework\Config\Config;
17
use Gacela\Framework\Config\ConfigFactory;
18
use Gacela\Framework\Container\Container;
19
use Gacela\Framework\Container\Locator;
20
use Gacela\Framework\Exception\GacelaNotBootstrappedException;
21
use Gacela\Framework\ServiceResolver\DocBlockResolverCache;
22
23
use function is_string;
24
use function sprintf;
25
26
final class Gacela
27
{
28
    private const GACELA_PHP_FILENAME = 'gacela.php';
29
30
    private static ?Container $mainContainer = null;
31
32
    private static ?string $appRootDir = null;
33
34
    /**
35
     * Define the entry point of Gacela.
36
     *
37 106
     * @param  null|Closure(GacelaConfig):void  $configFn
38
     */
39 106
    public static function bootstrap(string $appRootDir, ?Closure $configFn = null): void
40 106
    {
41
        self::$appRootDir = $appRootDir;
42 106
        self::$mainContainer = null;
43
44 106
        $setup = self::processConfigFnIntoSetup($configFn);
45 58
46
        if ($setup->shouldResetInMemoryCache()) {
47
            self::resetCache();
48 106
        }
49 106
50 106
        $config = Config::createWithSetup($setup);
51
        $config->setAppRootDir($appRootDir)
52 106
            ->init();
53
54
        self::runPlugins($config);
55
    }
56
57
    /**
58
     * @template T
59
     *
60
     * @param  class-string<T>  $className
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
61
     *
62 7
     * @return T|null
63
     */
64 7
    public static function get(string $className): mixed
65
    {
66
        return Locator::getSingleton($className, self::$mainContainer);
67
    }
68
69
    /**
70 38
     * Get the main dependency injection container.
71
     * This is the actual container created during bootstrap with all runtime bindings and frozen services.
72 38
     *
73 1
     * @throws GacelaNotBootstrappedException if Gacela has not been bootstrapped yet
74
     */
75 37
    public static function container(): Container
76
    {
77
        if (!self::$mainContainer instanceof Container) {
78
            throw new GacelaNotBootstrappedException();
79
        }
80
81 106
        return self::$mainContainer;
82
    }
83 106
84 74
    /**
85
     * Get the application root dir set when bootstrapping gacela
86
     */
87 32
    public static function rootDir(): string
88 32
    {
89 32
        if (self::$appRootDir === null) {
90 32
            throw new GacelaNotBootstrappedException();
91 32
        }
92 32
93
        return self::$appRootDir;
94 32
    }
95
96
    /**
97
     * Add an anonymous class as 'Config', 'Factory' or 'Provider' as a global resource
98 32
     * bound to the context that it is passed as second argument.
99
     *
100
     * @param  object|string  $context  It can be the string-key (file path) or the class/object itself.
101 58
     *                               If empty then the caller's file will be use
102
     */
103 58
    public static function addGlobal(object $resolvedClass, object|string $context = ''): void
104 58
    {
105 58
        if (is_string($context) && is_file($context)) {
106 58
            $context = basename($context, '.php');
107 58
        } elseif ($context === '') {
108 58
            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
109 58
            $callerFile = $trace[0]['file'] ?? __FILE__;
110 58
            $context = basename($callerFile, '.php');
111 58
        }
112 58
113 58
        AnonymousGlobal::addGlobal($context, $resolvedClass);
114
    }
115
116 106
    public static function overrideExistingResolvedClass(string $className, object $resolvedClass): void
117
    {
118 106
        AnonymousGlobal::overrideExistingResolvedClass($className, $resolvedClass);
119
    }
120 106
121
    /**
122 106
     * @param  null|Closure(GacelaConfig):void  $configFn
123
     */
124 5
    private static function processConfigFnIntoSetup(?Closure $configFn = null): SetupGacelaInterface
125 4
    {
126 1
        if ($configFn instanceof Closure) {
127
            return SetupGacela::fromCallable($configFn);
128 5
        }
129
130
        $gacelaFilePath = sprintf(
131
            '%s%s%s',
132
            self::rootDir(),
133
            DIRECTORY_SEPARATOR,
134
            self::GACELA_PHP_FILENAME,
135
        );
136
137
        if (is_file($gacelaFilePath)) {
138
            return SetupGacela::fromFile($gacelaFilePath);
139
        }
140
141
        return new SetupGacela();
142
    }
143
144
    private static function resetCache(): void
145
    {
146
        AnonymousGlobal::resetCache();
147
        AbstractFacade::resetCache();
148
        AbstractFactory::resetCache();
149
        AbstractClassResolver::resetCache();
150
        InMemoryCache::resetCache();
151
        GacelaFileCache::resetCache();
152
        DocBlockResolverCache::resetCache();
153
        ClassResolverCache::resetCache();
154
        ConfigFactory::resetCache();
155
        Config::resetInstance();
156
        Locator::resetInstance();
157
    }
158
159
    private static function runPlugins(Config $config): void
160
    {
161
        self::$mainContainer = Container::withConfig($config);
162
163
        $plugins = $config->getSetupGacela()->getPlugins();
164
165
        foreach ($plugins as $plugin) {
166
            /** @var callable $current */
167
            $current = is_string($plugin)
168
                ? self::$mainContainer->get($plugin)
169
                : $plugin;
170
171
            self::$mainContainer->resolve($current);
172
        }
173
    }
174
}
175