Completed
Push — master ( bbe0e7...1d2424 )
by jelmer
32:52 queued 27:17
created

app/Kernel.php (1 issue)

1
<?php
2
3
namespace ForkCMS\App;
4
5
use PDOException;
6
use Spoon;
7
use SpoonDatabaseException;
8
use Symfony\Component\DependencyInjection\ContainerBuilder;
9
use Symfony\Component\Filesystem\Filesystem;
10
use Symfony\Component\Finder\Finder;
11
use Symfony\Component\HttpFoundation\Response;
12
use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
13
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\HttpKernel\HttpKernelInterface;
16
use Backend\DependencyInjection\BackendExtension;
17
18
/**
19
 * The Kernel provides a proper way to load an environment and DI container.
20
 * It also handles requests and responses.
21
 */
22
abstract class Kernel extends BaseKernel
23
{
24
    /** @var Request We need this to check if a module is being installed */
25
    private $request;
26
27
    /**
28
     * Constructor.
29
     *
30
     * @param string $environment The environment
31
     * @param bool $enableDebug Whether to enable debugging or not
32
     *
33
     * @api
34
     */
35
    public function __construct(string $environment, bool $enableDebug)
36
    {
37
        $this->request = Request::createFromGlobals();
38
39
        parent::__construct($environment, $enableDebug);
40
        $this->boot();
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     *
46
     * @api
47
     */
48
    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true): Response
49
    {
50
        // boot if it hasn't booted yet
51
        $this->boot();
52
53
        return $this->getHttpKernel()->handle($request, $type, $catch);
54
    }
55
56
    /**
57
     * Boot and define the Fork Constants.
58
     */
59
    public function boot(): void
60
    {
61
        if ($this->booted) {
62
            return;
63
        }
64
65
        parent::boot();
66
67
        // define Fork constants
68
        $this->defineForkConstants();
0 ignored issues
show
Deprecated Code introduced by
The function ForkCMS\App\Kernel::defineForkConstants() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

68
        /** @scrutinizer ignore-deprecated */ $this->defineForkConstants();
Loading history...
69
    }
70
71
    /**
72
     * This will disappear in time in favour of container-driven parameters.
73
     *
74
     * @deprecated
75
     */
76
    public function defineForkConstants(): void
77
    {
78
        $container = $this->getContainer();
79
80
        Spoon::setDebug($container->getParameter('kernel.debug'));
81
        Spoon::setDebugEmail($container->getParameter('fork.debug_email'));
82
        Spoon::setDebugMessage($container->getParameter('fork.debug_message'));
83
        Spoon::setCharset($container->getParameter('kernel.charset'));
84
85
        /**
86
         * @deprecated SPOON_* constants are deprecated in favour of Spoon::set*().
87
         * Will be removed in the next major release.
88
         */
89
        defined('PATH_WWW') || define('PATH_WWW', realpath($container->getParameter('site.path_www')));
90
91
        defined('SITE_DEFAULT_LANGUAGE') || define('SITE_DEFAULT_LANGUAGE', $container->getParameter('site.default_language'));
92
        defined('SITE_DEFAULT_TITLE') || define('SITE_DEFAULT_TITLE', $container->getParameter('site.default_title'));
93
        defined('SITE_MULTILANGUAGE') || define('SITE_MULTILANGUAGE', $container->getParameter('site.multilanguage'));
94
        defined('SITE_DOMAIN') || define('SITE_DOMAIN', $container->getParameter('site.domain'));
95
        defined('SITE_PROTOCOL') || define('SITE_PROTOCOL', $container->getParameter('site.protocol'));
96
        defined('SITE_URL') || define('SITE_URL', SITE_PROTOCOL . '://' . SITE_DOMAIN);
97
98
        defined('FORK_VERSION') || define('FORK_VERSION', $container->getParameter('fork.version'));
99
100
        defined('ACTION_GROUP_TAG') || define('ACTION_GROUP_TAG', $container->getParameter('action.group_tag'));
101
        defined('ACTION_RIGHTS_LEVEL') || define('ACTION_RIGHTS_LEVEL', $container->getParameter('action.rights_level'));
102
103
        defined('BACKEND_PATH') || define('BACKEND_PATH', PATH_WWW . '/src/Backend');
104
        defined('BACKEND_CACHE_PATH') || define('BACKEND_CACHE_PATH', BACKEND_PATH . '/Cache');
105
        defined('BACKEND_CORE_PATH') || define('BACKEND_CORE_PATH', BACKEND_PATH . '/Core');
106
        defined('BACKEND_MODULES_PATH') || define('BACKEND_MODULES_PATH', BACKEND_PATH . '/Modules');
107
        defined('BACKEND_CORE_URL') || define('BACKEND_CORE_URL', '/src/Backend/Core');
108
        defined('BACKEND_CACHE_URL') || define('BACKEND_CACHE_URL', '/src/Backend/Cache');
109
110
        defined('FRONTEND_PATH') || define('FRONTEND_PATH', PATH_WWW . '/src/Frontend');
111
        defined('FRONTEND_CACHE_PATH') || define('FRONTEND_CACHE_PATH', FRONTEND_PATH . '/Cache');
112
        defined('FRONTEND_THEMES_PATH') || define('FRONTEND_THEMES_PATH', FRONTEND_PATH . '/Themes');
113
        defined('FRONTEND_CORE_PATH') || define('FRONTEND_CORE_PATH', FRONTEND_PATH . '/Core');
114
        defined('FRONTEND_MODULES_PATH') || define('FRONTEND_MODULES_PATH', FRONTEND_PATH . '/Modules');
115
        defined('FRONTEND_FILES_PATH') || define('FRONTEND_FILES_PATH', FRONTEND_PATH . '/Files');
116
        defined('FRONTEND_FILES_URL') || define('FRONTEND_FILES_URL', '/src/Frontend/Files');
117
        defined('FRONTEND_CORE_URL') || define('FRONTEND_CORE_URL', '/src/Frontend/Core');
118
        defined('FRONTEND_CACHE_URL') || define('FRONTEND_CACHE_URL', '/src/Frontend/Cache');
119
    }
120
121
    /**
122
     * Builds the service container.
123
     *
124
     * @throws \RuntimeException
125
     *
126
     * @return ContainerBuilder The compiled service container
127
     */
128
    protected function buildContainer()
129
    {
130
        $container = parent::buildContainer();
131
132
        $installedModules = $this->getInstalledModules($container);
133
134
        $container->setParameter('installed_modules', $installedModules);
135
136
        foreach ($installedModules as $module) {
137
            $class = 'Backend\\Modules\\' . $module . '\\DependencyInjection\\' . $module . 'Extension';
138
139
            if (class_exists($class)) {
140
                $container->registerExtension(new $class());
141
            }
142
        }
143
144
        $container->registerExtension(new BackendExtension());
145
146
        // ensure these extensions are implicitly loaded
147
        $container->getCompilerPassConfig()->setMergePass(
148
            new MergeExtensionConfigurationPass(array_keys($container->getExtensions()))
149
        );
150
151
        return $container;
152
    }
153
154
    private function getInstalledModules(ContainerBuilder $containerBuilder): array
155
    {
156
        // on installation all modules should be loaded
157
        if ($this->environment === 'install' || $this->environment === 'test') {
158
            return $this->getAllPossibleModuleNames();
159
        }
160
161
        $moduleNames = [];
162
        if ($this->isInstallingModule()) {
163
            $moduleNames[] = $this->request->query->get('module');
164
        }
165
166
        try {
167
            $moduleNames = array_merge(
168
                $moduleNames,
169
                (array) $containerBuilder->get('database')->getColumn(
170
                    'SELECT name FROM modules'
171
                )
172
            );
173
        } catch (SpoonDatabaseException $e) {
174
            $moduleNames = [];
175
        } catch (PDOException $e) {
176
            // fork is probably not installed yet
177
            $moduleNames = [];
178
        }
179
180
        if (empty($moduleNames)) {
181
            return $this->getAllPossibleModuleNames();
182
        }
183
184
        return $moduleNames;
185
    }
186
187
    public function isInstallingModule(): bool
188
    {
189
        return preg_match('/\/private(\/\w\w)?\/extensions\/install_module\?/', $this->request->getRequestUri())
190
               && $this->request->query->has('module')
191
               && in_array($this->request->query->get('module'), $this->getAllPossibleModuleNames());
192
    }
193
194
    private function getAllPossibleModuleNames(): array
195
    {
196
        $moduleNames = [];
197
        $finder = new Finder();
198
199
        $directories = $finder->directories()->in(__DIR__ . '/../src/Backend/Modules')->depth(0);
200
201
        foreach ($directories->getIterator() as $directory) {
202
            $moduleNames[] = $directory->getFilename();
203
        }
204
205
        return $moduleNames;
206
    }
207
208
    protected function initializeContainer(): void
209
    {
210
        // remove the cache dir when installing a module to trigger rebuilding the kernel
211
        if ($this->isInstallingModule()) {
212
            $fileSystem = new Filesystem();
213
            $fileSystem->remove($this->getCacheDir().'/'.$this->getContainerClass().'.php');
214
        }
215
216
        parent::initializeContainer();
217
    }
218
219
    public function getLogDir(): string
220
    {
221
        return dirname(__DIR__).'/var/logs/' . $this->environment;
222
    }
223
224
    public function getCacheDir(): string
225
    {
226
        return dirname(__DIR__) . '/var/cache/' . $this->environment;
227
    }
228
}
229