Completed
Pull Request — master (#6706)
by Damian
09:02
created

CoreConfigFactory::inst()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 9.4285
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 Psr\SimpleCache\CacheInterface;
10
use SilverStripe\Config\Collections\CachedConfigCollection;
11
use SilverStripe\Config\Collections\MemoryConfigCollection;
12
use SilverStripe\Config\Transformer\PrivateStaticTransformer;
13
use SilverStripe\Config\Transformer\YamlTransformer;
14
use SilverStripe\Control\Director;
15
use SilverStripe\Core\Cache\CacheFactory;
16
use SilverStripe\Core\Config\Middleware\ExtensionMiddleware;
17
use SilverStripe\Core\Config\Middleware\InheritanceMiddleware;
18
use SilverStripe\Core\Manifest\ClassLoader;
19
use SilverStripe\Core\Manifest\ModuleLoader;
20
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
21
use Symfony\Component\Finder\Finder;
22
23
/**
24
 * Factory for silverstripe configs
25
 */
26
class CoreConfigFactory
27
{
28
    /**
29
     * @var static
30
     */
31
    protected static $inst = null;
32
33
    /**
34
     * @return static
35
     */
36
    public static function inst()
37
    {
38
        if (!self::$inst) {
39
            self::$inst = new static();
40
        }
41
        return self::$inst;
42
    }
43
44
    /**
45
     * Create root application config.
46
     * This will be an immutable cached config,
47
     * which conditionally generates a nested "core" config.
48
     *
49
     * @param bool $flush
50
     * @param CacheFactory $cacheFactory
51
     * @return CachedConfigCollection
52
     */
53
    public function createRoot($flush, CacheFactory $cacheFactory)
54
    {
55
        $instance = new CachedConfigCollection();
56
57
        // Create config cache
58
        $cache = $cacheFactory->create(CacheInterface::class.'.configcache', [
59
            'namespace' => 'configcache'
60
        ]);
61
        $instance->setCache($cache);
62
        $instance->setFlush($flush);
63
64
        // Set collection creator
65
        $instance->setCollectionCreator(function () {
66
            return $this->createCore();
67
        });
68
69
        return $instance;
70
    }
71
72
    /**
73
     * Rebuild new uncached config, which is mutable
74
     *
75
     * @return MemoryConfigCollection
76
     */
77
    public function createCore()
78
    {
79
        $config = new MemoryConfigCollection();
80
81
        // Set default middleware
82
        $config->setMiddlewares([
83
            new InheritanceMiddleware(Config::UNINHERITED),
84
            new ExtensionMiddleware(Config::EXCLUDE_EXTRA_SOURCES),
85
        ]);
86
87
        // Transform
88
        $config->transform([
89
            $this->buildStaticTransformer(),
90
            $this->buildYamlTransformer()
91
        ]);
92
93
        return $config;
94
    }
95
96
    /**
97
     * @return YamlTransformer
98
     */
99
    protected function buildYamlTransformer()
100
    {
101
        // Get all module dirs
102
        $modules = ModuleLoader::instance()->getManifest()->getModules();
103
        $dirs = [];
104
        foreach ($modules as $module) {
105
            // Load from _config dirs
106
            $path = $module->getPath() . '/_config';
107
            if (is_dir($path)) {
108
                $dirs[] = $path;
109
            }
110
        }
111
112
        return $this->buildYamlTransformerForPath($dirs);
113
    }
114
115
    /**
116
     * @return PrivateStaticTransformer
117
     */
118
    public function buildStaticTransformer()
119
    {
120
        return new PrivateStaticTransformer(function () {
121
            $classes = ClassLoader::instance()->getManifest()->getClasses();
122
            return array_keys($classes);
123
        });
124
    }
125
126
    /**
127
     * @param array|string $dirs Base dir to load from
128
     * @return YamlTransformer
129
     */
130
    public function buildYamlTransformerForPath($dirs)
131
    {
132
        // Construct
133
        $transformer = YamlTransformer::create(
134
            BASE_PATH,
135
            Finder::create()
136
                ->in($dirs)
137
                ->files()
138
                ->name('/\.(yml|yaml)$/')
139
        );
140
141
        // Add default rules
142
        $envvarset = function ($var, $value = null) {
143
            if (getenv($var) === false) {
144
                return false;
145
            }
146
            if ($value) {
147
                return getenv($var) === $value;
148
            }
149
            return true;
150
        };
151
        $constantdefined = function ($const, $value = null) {
152
            if (!defined($const)) {
153
                return false;
154
            }
155
            if ($value) {
156
                return constant($const) === $value;
157
            }
158
            return true;
159
        };
160
        return $transformer
161
            ->addRule('classexists', function ($class) {
162
                return class_exists($class);
163
            })
164
            ->addRule('envvarset', $envvarset)
165
            ->addRule('constantdefined', $constantdefined)
166
            ->addRule(
167
                'envorconstant',
168
                // Composite rule
169
                function ($name, $value = null) use ($envvarset, $constantdefined) {
170
                    return $envvarset($name, $value) || $constantdefined($name, $value);
171
                }
172
            )
173
            ->addRule('environment', function ($env) {
174
                $current = Director::get_environment_type();
175
                return strtolower($current) === strtolower($env);
176
            })
177
            ->addRule('moduleexists', function ($module) {
178
                return ModuleLoader::instance()->getManifest()->moduleExists($module);
179
            });
180
    }
181
}
182