Completed
Push — master ( e4daf7...e7a4df )
by Daniel
09:00
created

CoreConfigFactory   B

Complexity

Total Complexity 17

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 17

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 180
rs 7.8571
c 2
b 0
f 0
wmc 17
lcom 2
cbo 17

8 Methods

Rating   Name   Duplication   Size   Complexity  
A inst() 0 7 2
A createRoot() 0 15 1
A createCore() 0 18 1
A buildYamlTransformer() 0 15 3
A buildStaticTransformer() 0 7 1
B buildYamlTransformerForPath() 0 51 6
A createPool() 0 6 1
A createLogger() 0 10 2
1
<?php
2
3
namespace SilverStripe\Core\Config;
4
5
use Monolog\Handler\ErrorLogHandler;
6
use Monolog\Handler\StreamHandler;
7
use Monolog\Logger;
8
use Psr\Log\LoggerInterface;
9
use SilverStripe\Config\Collections\CachedConfigCollection;
10
use SilverStripe\Config\Collections\MemoryConfigCollection;
11
use SilverStripe\Config\Transformer\PrivateStaticTransformer;
12
use SilverStripe\Config\Transformer\YamlTransformer;
13
use SilverStripe\Control\Director;
14
use SilverStripe\Core\Config\Middleware\ExtensionMiddleware;
15
use SilverStripe\Core\Config\Middleware\InheritanceMiddleware;
16
use SilverStripe\Core\Manifest\ClassLoader;
17
use SilverStripe\Core\Manifest\ModuleLoader;
18
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
19
use Symfony\Component\Finder\Finder;
20
21
/**
22
 * Factory for silverstripe configs
23
 */
24
class CoreConfigFactory
25
{
26
    /**
27
     * @var static
28
     */
29
    protected static $inst = null;
30
31
    /**
32
     * @return static
33
     */
34
    public static function inst()
35
    {
36
        if (!self::$inst) {
37
            self::$inst = new static();
38
        }
39
        return self::$inst;
40
    }
41
42
    /**
43
     * Create root application config.
44
     * This will be an immutable cached config,
45
     * which conditionally generates a nested "core" config.
46
     *
47
     * @param bool $flush
48
     * @return CachedConfigCollection
49
     */
50
    public function createRoot($flush)
51
    {
52
        $instance = new CachedConfigCollection();
53
54
        // Set root cache
55
        $instance->setPool($this->createPool());
56
        $instance->setFlush($flush);
57
58
        // Set collection creator
59
        $instance->setCollectionCreator(function () {
60
            return $this->createCore();
61
        });
62
63
        return $instance;
64
    }
65
66
    /**
67
     * Rebuild new uncached config, which is mutable
68
     *
69
     * @return MemoryConfigCollection
70
     */
71
    public function createCore()
72
    {
73
        $config = new MemoryConfigCollection();
74
75
        // Set default middleware
76
        $config->setMiddlewares([
77
            new InheritanceMiddleware(Config::UNINHERITED),
78
            new ExtensionMiddleware(Config::EXCLUDE_EXTRA_SOURCES),
79
        ]);
80
81
        // Transform
82
        $config->transform([
83
            $this->buildStaticTransformer(),
84
            $this->buildYamlTransformer()
85
        ]);
86
87
        return $config;
88
    }
89
90
    /**
91
     * @return YamlTransformer
92
     */
93
    protected function buildYamlTransformer()
94
    {
95
        // Get all module dirs
96
        $modules = ModuleLoader::instance()->getManifest()->getModules();
97
        $dirs = [];
98
        foreach ($modules as $module) {
99
            // Load from _config dirs
100
            $path = $module->getPath() . '/_config';
101
            if (is_dir($path)) {
102
                $dirs[] = $path;
103
            }
104
        }
105
106
        return $this->buildYamlTransformerForPath($dirs);
107
    }
108
109
    /**
110
     * @return PrivateStaticTransformer
111
     */
112
    public function buildStaticTransformer()
113
    {
114
        return new PrivateStaticTransformer(function () {
115
            $classes = ClassLoader::instance()->getManifest()->getClasses();
116
            return array_keys($classes);
117
        });
118
    }
119
120
    /**
121
     * @param array|string $dirs Base dir to load from
122
     * @return YamlTransformer
123
     */
124
    public function buildYamlTransformerForPath($dirs)
125
    {
126
        // Construct
127
        $transformer = YamlTransformer::create(
128
            BASE_PATH,
129
            Finder::create()
130
                ->in($dirs)
131
                ->files()
132
                ->name('/\.(yml|yaml)$/')
133
        );
134
135
        // Add default rules
136
        $envvarset = function ($var, $value = null) {
137
            if (getenv($var) === false) {
138
                return false;
139
            }
140
            if ($value) {
141
                return getenv($var) === $value;
142
            }
143
            return true;
144
        };
145
        $constantdefined = function ($const, $value = null) {
146
            if (!defined($const)) {
147
                return false;
148
            }
149
            if ($value) {
150
                return constant($const) === $value;
151
            }
152
            return true;
153
        };
154
        return $transformer
155
            ->addRule('classexists', function ($class) {
156
                return class_exists($class);
157
            })
158
            ->addRule('envvarset', $envvarset)
159
            ->addRule('constantdefined', $constantdefined)
160
            ->addRule(
161
                'envorconstant',
162
                // Composite rule
163
                function ($name, $value = null) use ($envvarset, $constantdefined) {
164
                    return $envvarset($name, $value) || $constantdefined($name, $value);
165
                }
166
            )
167
            ->addRule('environment', function ($env) {
168
                $current = Director::get_environment_type();
169
                return strtolower($current) === strtolower($env);
170
            })
171
            ->addRule('moduleexists', function ($module) {
172
                return ModuleLoader::instance()->getManifest()->moduleExists($module);
173
            });
174
    }
175
176
    /**
177
     * @todo Refactor bootstrapping of manifest caching into app object
178
     * @return FilesystemAdapter
179
     */
180
    protected function createPool()
181
    {
182
        $cache = new FilesystemAdapter('configcache', 0, getTempFolder());
183
        $cache->setLogger($this->createLogger());
184
        return $cache;
185
    }
186
187
    /**
188
     * Create default error logger
189
     *
190
     * @todo Refactor bootstrapping of manifest logging into app object
191
     * @return LoggerInterface
192
     */
193
    protected function createLogger()
194
    {
195
        $logger = new Logger("configcache-log");
196
        if (Director::isDev()) {
197
            $logger->pushHandler(new StreamHandler('php://output'));
198
        } else {
199
            $logger->pushHandler(new ErrorLogHandler());
200
        }
201
        return $logger;
202
    }
203
}
204