Passed
Push — master ( 482ae9...59f703 )
by Andreas
22:54
created

midcom_application::registerBundles()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
/**
3
 * @package midcom
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpKernel\HttpKernelInterface;
11
use Symfony\Component\HttpKernel\Kernel;
12
use Symfony\Component\Config\Loader\LoaderInterface;
13
use Symfony\Component\DependencyInjection\ContainerBuilder;
14
use midcom\dependencyInjection\loggerPass;
15
use midcom\dependencyInjection\componentPass;
16
use midcom\dependencyInjection\indexerPass;
17
use midcom\dependencyInjection\cachePass;
18
19
/**
20
 * Main controlling instance of the MidCOM Framework
21
 *
22
 * @property midcom_services_i18n $i18n
23
 * @property midcom_helper__componentloader $componentloader
24
 * @property midcom_services_dbclassloader $dbclassloader
25
 * @property midcom_helper__dbfactory $dbfactory
26
 * @property midcom_helper_head $head
27
 * @property midcom_helper__styleloader $style
28
 * @property midcom_services_auth $auth
29
 * @property midcom_services_permalinks $permalinks
30
 * @property midcom_services_toolbars $toolbars
31
 * @property midcom_services_uimessages $uimessages
32
 * @property midcom_services_metadata $metadata
33
 * @property midcom_services_rcs $rcs
34
 * @property midcom_services__sessioning $session
35
 * @property midcom_services_indexer $indexer
36
 * @property midcom_config $config
37
 * @property midcom_services_cache $cache
38
 * @property Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
39
 * @property midcom_debug $debug
40
 * @package midcom
41
 */
42
class midcom_application extends Kernel
43
{
44
    /**
45
     * Host prefix cache to avoid computing it each time.
46
     *
47
     * @var string
48
     * @see get_host_prefix()
49
     */
50
    private $_cached_host_prefix = '';
51
52
    /**
53
     * Page prefix cache to avoid computing it each time.
54
     *
55
     * @var string
56
     * @see get_page_prefix()
57
     */
58
    private $_cached_page_prefix = '';
59
60
    /**
61
     * @var Request
62
     */
63
    private $request;
64
65
    /**
66
     * Set this variable to true during the handle phase of your component to
67
     * not show the site's style around the component output. This is mainly
68
     * targeted at XML output like RSS feeds and similar things. The output
69
     * handler of the site, excluding the style-init/-finish tags will be executed
70
     * immediately after the handle phase
71
     *
72
     * Changing this flag after the handle phase or for dynamically loaded
73
     * components won't change anything.
74
     *
75
     * @var boolean
76
     */
77
    public $skip_page_style = false;
78
79
    private $project_dir;
80
81
    /**
82
     * @var midcom_config
83
     */
84
    private $cfg;
85
86
    public function __construct(string $environment, bool $debug)
87
    {
88
        midcom_compat_environment::initialize();
89
        $this->request = Request::createFromGlobals();
90
        $this->cfg = new midcom_config;
91
        parent::__construct($environment, $debug);
92
    }
93
94
    public function registerContainerConfiguration(LoaderInterface $loader)
95
    {
96
        $loader->load(__DIR__ . '/config/services.yml');
97
        if (file_exists($this->getProjectDir() . '/config/services.yml')) {
98
            $loader->load($this->getProjectDir() . '/config/services.yml');
99
        }
100
        if ($classes = midcom::get_registered_service_classes()) {
101
            $loader->load(function (ContainerBuilder $container) use ($classes) {
102
                foreach ($classes as $id => $class) {
103
                    $container->findDefinition($id)->setClass($class);
104
                }
105
            });
106
        }
107
    }
108
109
    protected function initializeContainer()
110
    {
111
        parent::initializeContainer();
112
        $this->container->set('config', $this->cfg);
113
    }
114
115
    protected function build(ContainerBuilder $container)
116
    {
117
        parent::build($container);
118
        $container->addCompilerPass(new loggerPass($this->cfg));
119
        $container->addCompilerPass(new componentPass($this->cfg));
120
        $container->addCompilerPass(new cachePass($this->cfg));
121
        $container->addCompilerPass(new indexerPass($this->cfg));
122
    }
123
124
    public function registerBundles()
125
    {
126
        return [];
127
    }
128
129
    public function getProjectDir()
130
    {
131
        if ($this->project_dir === null) {
132
            if (basename(dirname(__DIR__, 4)) === 'vendor') {
133
                // this is the case where we're installed as a dependency
134
                $this->project_dir = dirname(__DIR__, 5);
135
            } else {
136
                $this->project_dir = dirname(__DIR__, 2);
137
            }
138
        }
139
        return $this->project_dir;
140
    }
141
142 325
    public function getCacheDir()
143
    {
144 325
        return $this->cfg->get('cache_base_directory') ?: parent::getCacheDir();
145
    }
146
147
    /**
148
     * Magic getter for service loading
149
     */
150 736
    public function __get($key)
151
    {
152 736
        return $this->getContainer()->get($key);
153
    }
154
155
    /**
156
     * Magic setter
157
     */
158
    public function __set($key, $value)
159
    {
160
        $this->getContainer()->set($key, $value);
161
    }
162
163
    /* *************************************************************************
164
     * Control framework:
165
     * codeinit      - Handle the current request
166
     * dynamic_load   - Dynamically load and execute a URL
167
     * finish         - Cleanup Work
168
     */
169
170
    /**
171
     * Initialize the URL parser and process the request.
172
     *
173
     * This function must be called before any output starts.
174
     */
175
    public function codeinit()
176
    {
177
        try {
178
            $this->handle($this->request)->send();
179
        } catch (Error $e) {
180
            $this->getHttpKernel()->terminateWithException($e);
0 ignored issues
show
Bug introduced by
The method terminateWithException() does not exist on Symfony\Component\HttpKernel\HttpKernelInterface. It seems like you code against a sub-type of Symfony\Component\HttpKernel\HttpKernelInterface such as Symfony\Component\HttpKernel\HttpKernel. ( Ignorable by Annotation )

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

180
            $this->getHttpKernel()->/** @scrutinizer ignore-call */ terminateWithException($e);
Loading history...
181
        }
182
    }
183
184
    /**
185
     * Dynamically execute a subrequest and insert its output in place of the
186
     * function call.
187
     *
188
     * It tries to load the component referenced with the URL $url and executes
189
     * it as if it was used as primary component.
190
     *
191
     * This is only possible if the system is in the Page-Style output phase. It
192
     * cannot be used within code-init or during the output phase of another
193
     * component.
194
     *
195
     * Example code, executed on a site's homepage, it will load the news listing from
196
     * the given URL and display it using a substyle of the node style that is assigned
197
     * to the loaded one:
198
     *
199
     * <code>
200
     * $blog = '/blog/latest/3/';
201
     * $substyle = 'homepage';
202
     * midcom::get()->dynamic_load("/midcom-substyle-{$substyle}/{$blog}");
203
     * </code>
204
     *
205
     * Results of dynamic_loads are cached with the system cache strategy
206
     *
207
     * @param string $url                The URL, relative to the Midgard Page, that is to be requested.
208
     */
209 16
    public function dynamic_load(string $url, string $substyle = '')
210
    {
211 16
        debug_add("Dynamic load of URL {$url}");
212 16
        $url = midcom_connection::get_url('prefix') . $url;
213
214
        // Determine new Context ID and set current context,
215
        // enter that context and prepare its data structure.
216 16
        $oldcontext = midcom_core_context::get();
217 16
        $context = midcom_core_context::enter($url, $oldcontext->get_key(MIDCOM_CONTEXT_ROOTTOPIC));
0 ignored issues
show
Bug introduced by
It seems like $oldcontext->get_key(MIDCOM_CONTEXT_ROOTTOPIC) can also be of type false; however, parameter $topic of midcom_core_context::enter() does only seem to accept midcom_db_topic|null, maybe add an additional type check? ( Ignorable by Annotation )

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

217
        $context = midcom_core_context::enter($url, /** @scrutinizer ignore-type */ $oldcontext->get_key(MIDCOM_CONTEXT_ROOTTOPIC));
Loading history...
218 16
        if ($substyle) {
219
            $context->set_key(MIDCOM_CONTEXT_SUBSTYLE, $substyle);
220
        }
221
222 16
        $request = $this->request->duplicate([], null, []);
223 16
        $request->attributes->set('context', $context);
224
225 16
        $cached = $this->cache->content->check_dl_hit($request);
226 16
        if ($cached !== false) {
227
            echo $cached;
228
            midcom_core_context::leave();
229
            return;
230
        }
231
232 16
        $backup = $this->skip_page_style;
233 16
        $this->skip_page_style = true;
234
        try {
235 16
            $response = $this->handle($request, HttpKernelInterface::SUB_REQUEST, false);
236 12
        } catch (midcom_error $e) {
237 12
            if ($e instanceof midcom_error_notfound || $e instanceof midcom_error_forbidden) {
238 12
                $e->log();
239 12
                midcom_core_context::leave();
240 12
                return;
241
            }
242
            throw $e;
243 4
        } finally {
244 16
            $this->skip_page_style = $backup;
245
        }
246
247 4
        $dl_cache_data = $response->getContent();
248 4
        echo $dl_cache_data;
249
250
        /* Cache DL the content */
251 4
        $this->cache->content->store_dl_content($context->id, $dl_cache_data, $request);
252
253 4
        midcom_core_context::leave();
254 4
    }
255
256
    /**
257
     * Exit from the framework, execute after all output has been made.
258
     *
259
     * <b>WARNING:</b> Anything done after calling this method will be lost.
260
     */
261
    public function finish()
262
    {
263
        debug_add("End of MidCOM run: " . $this->request->server->get('REQUEST_URI'));
264
        _midcom_stop_request();
265
    }
266
267
    /* *************************************************************************
268
     * Framework Access Helper functions
269
     */
270
271
    /**
272
     * Retrieves the name of the current host, fully qualified with protocol and
273
     * port (http[s]://www.my.domain.com[:1234])
274
     */
275 37
    function get_host_name() : string
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
276
    {
277 37
        return $this->request->getSchemeAndHttpHost();
278
    }
279
280
    /**
281
     * Return the prefix required to build relative links on the current site.
282
     * This includes the http[s] prefix, the hosts port (if necessary) and the
283
     * base url of the Midgard Page. Be aware, that this does *not* point to the
284
     * base host of the site.
285
     *
286
     * e.g. something like http[s]://www.domain.com[:8080]/host_prefix/page_prefix/
287
     */
288
    function get_page_prefix() : string
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
289
    {
290
        if (!$this->_cached_page_prefix) {
291
            $host_name = $this->get_host_name();
292
            $this->_cached_page_prefix = $host_name . midcom_connection::get_url('self');
293
        }
294
295
        return $this->_cached_page_prefix;
296
    }
297
298
    /**
299
     * Return the prefix required to build relative links on the current site.
300
     * This includes the http[s] prefix, the hosts port (if necessary) and the
301
     * base url of the main host. This is not necessarily the currently active
302
     * MidCOM Page however, use the get_page_prefix() function for that.
303
     *
304
     * e.g. something like http[s]://www.domain.com[:8080]/host_prefix/
305
     */
306 7
    function get_host_prefix() : string
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
307
    {
308 7
        if (!$this->_cached_host_prefix) {
309 1
            $host_name = $this->get_host_name();
310 1
            $host_prefix = midcom_connection::get_url('prefix');
311 1
            if (substr($host_prefix, 0, 1) != '/') {
312
                $host_prefix = "/{$host_prefix}";
313
            }
314 1
            if (substr($host_prefix, -1, 1) != '/') {
315
                $host_prefix .= '/';
316
            }
317 1
            $this->_cached_host_prefix = "{$host_name}{$host_prefix}";
318
        }
319
320 7
        return $this->_cached_host_prefix;
321
    }
322
323
    /* *************************************************************************
324
     * Generic Helper Functions not directly related with MidCOM:
325
     *
326
     * relocate           - executes a HTTP relocation to the given URL
327
     */
328
329
    /**
330
     * Sends a header out to the client.
331
     *
332
     * This function is syntactically identical to
333
     * the regular PHP header() function, but is integrated into the framework. Every
334
     * Header you sent must go through this function or it might be lost later on;
335
     * this is especially important with caching.
336
     *
337
     * @param string $header    The header to send.
338
     * @param integer $response_code HTTP response code to send with the header
339
     */
340 17
    public function header($header, $response_code = null)
341
    {
342 17
        $this->cache->content->register_sent_header($header);
343 17
        midcom_compat_environment::get()->header($header, true, $response_code);
344 17
    }
345
346
    /**
347
     * Relocate to another URL.
348
     *
349
     * Note, that this function automatically makes the page uncacheable, calls
350
     * midcom_finish and exit, so it will never return. If the headers have already
351
     * been sent, this will leave you with a partially completed page, so beware.
352
     *
353
     * @param string $url    The URL to redirect to, will be preprocessed as outlined above.
354
     * @param int $response_code HTTP response code to send with the relocation, from 3xx series
355
     */
356
    public function relocate($url, $response_code = 302)
357
    {
358
        $response = new midcom_response_relocate($url, $response_code);
359
        $response->send();
360
        $this->finish();
361
    }
362
363
    /**
364
     * Raise some PHP limits for resource-intensive tasks
365
     */
366 8
    public function disable_limits()
367
    {
368 8
        $stat = @ini_set('max_execution_time', $this->config->get('midcom_max_execution_time'));
369 8
        if (false === $stat) {
370
            debug_add('ini_set("max_execution_time", ' . $this->config->get('midcom_max_execution_time') . ') returned false', MIDCOM_LOG_WARN);
371
        }
372 8
        $stat = @ini_set('memory_limit', $this->config->get('midcom_max_memory'));
373 8
        if (false === $stat) {
374
            debug_add('ini_set("memory_limit", ' . $this->config->get('midcom_max_memory') . ') returned false', MIDCOM_LOG_WARN);
375
        }
376 8
    }
377
}
378