Passed
Push — master ( 6bc8e4...08f33e )
by Andreas
30:22
created

midcom_application::getCacheDir()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

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

164
            $this->getHttpKernel()->/** @scrutinizer ignore-call */ terminateWithException($e);
Loading history...
165
        }
166
    }
167
168
    /**
169
     * Dynamically execute a subrequest and insert its output in place of the
170
     * function call.
171
     *
172
     * It tries to load the component referenced with the URL $url and executes
173
     * it as if it was used as primary component.
174
     *
175
     * This is only possible if the system is in the Page-Style output phase. It
176
     * cannot be used within code-init or during the output phase of another
177
     * component.
178
     *
179
     * Example code, executed on a site's homepage, it will load the news listing from
180
     * the given URL and display it using a substyle of the node style that is assigned
181
     * to the loaded one:
182
     *
183
     * <code>
184
     * $blog = '/blog/latest/3/';
185
     * $substyle = 'homepage';
186
     * midcom::get()->dynamic_load("/midcom-substyle-{$substyle}/{$blog}");
187
     * </code>
188
     *
189
     * Results of dynamic_loads are cached with the system cache strategy
190
     *
191
     * @param string $url                The URL, relative to the Midgard Page, that is to be requested.
192
     */
193 16
    public function dynamic_load($url)
194
    {
195 16
        debug_add("Dynamic load of URL {$url}");
196 16
        $url = midcom_connection::get_url('prefix') . $url;
197
198
        // Determine new Context ID and set current context,
199
        // enter that context and prepare its data structure.
200 16
        $oldcontext = midcom_core_context::get();
201 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

201
        $context = midcom_core_context::enter($url, /** @scrutinizer ignore-type */ $oldcontext->get_key(MIDCOM_CONTEXT_ROOTTOPIC));
Loading history...
202
203 16
        $request = $this->request->duplicate([], null, []);
204 16
        $request->attributes->set('context', $context);
205
206 16
        $cached = $this->cache->content->check_dl_hit($request);
207 16
        if ($cached !== false) {
208
            echo $cached;
209
            midcom_core_context::leave();
210
            return;
211
        }
212
213 16
        $backup = $this->skip_page_style;
214 16
        $this->skip_page_style = true;
215
        try {
216 16
            $response = $this->handle($request, HttpKernelInterface::SUB_REQUEST, false);
217 12
        } catch (midcom_error $e) {
218 12
            if ($e instanceof midcom_error_notfound || $e instanceof midcom_error_forbidden) {
219 12
                $e->log();
220 12
                midcom_core_context::leave();
221 12
                return;
222
            }
223
            throw $e;
224 4
        } finally {
225 16
            $this->skip_page_style = $backup;
226
        }
227
228 4
        $dl_cache_data = $response->getContent();
229 4
        echo $dl_cache_data;
230
231
        /* Cache DL the content */
232 4
        $this->cache->content->store_dl_content($context->id, $dl_cache_data, $request);
233
234 4
        midcom_core_context::leave();
235 4
    }
236
237
    /**
238
     * Exit from the framework, execute after all output has been made.
239
     *
240
     * <b>WARNING:</b> Anything done after calling this method will be lost.
241
     */
242
    public function finish()
243
    {
244
        debug_add("End of MidCOM run: " . $this->request->server->get('REQUEST_URI'));
245
        _midcom_stop_request();
246
    }
247
248
    /* *************************************************************************
249
     * Framework Access Helper functions
250
     */
251
252
    /**
253
     * Retrieves the name of the current host, fully qualified with protocol and
254
     * port (http[s]://www.my.domain.com[:1234])
255
     */
256 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...
257
    {
258 37
        return $this->request->getSchemeAndHttpHost();
259
    }
260
261
    /**
262
     * Return the prefix required to build relative links on the current site.
263
     * This includes the http[s] prefix, the hosts port (if necessary) and the
264
     * base url of the Midgard Page. Be aware, that this does *not* point to the
265
     * base host of the site.
266
     *
267
     * e.g. something like http[s]://www.domain.com[:8080]/host_prefix/page_prefix/
268
     */
269
    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...
270
    {
271
        if (!$this->_cached_page_prefix) {
272
            $host_name = $this->get_host_name();
273
            $this->_cached_page_prefix = $host_name . midcom_connection::get_url('self');
274
        }
275
276
        return $this->_cached_page_prefix;
277
    }
278
279
    /**
280
     * Return the prefix required to build relative links on the current site.
281
     * This includes the http[s] prefix, the hosts port (if necessary) and the
282
     * base url of the main host. This is not necessarily the currently active
283
     * MidCOM Page however, use the get_page_prefix() function for that.
284
     *
285
     * e.g. something like http[s]://www.domain.com[:8080]/host_prefix/
286
     */
287 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...
288
    {
289 7
        if (!$this->_cached_host_prefix) {
290 1
            $host_name = $this->get_host_name();
291 1
            $host_prefix = midcom_connection::get_url('prefix');
292 1
            if (substr($host_prefix, 0, 1) != '/') {
293
                $host_prefix = "/{$host_prefix}";
294
            }
295 1
            if (substr($host_prefix, -1, 1) != '/') {
296
                $host_prefix .= '/';
297
            }
298 1
            $this->_cached_host_prefix = "{$host_name}{$host_prefix}";
299
        }
300
301 7
        return $this->_cached_host_prefix;
302
    }
303
304
    /* *************************************************************************
305
     * Generic Helper Functions not directly related with MidCOM:
306
     *
307
     * relocate           - executes a HTTP relocation to the given URL
308
     */
309
310
    /**
311
     * Sends a header out to the client.
312
     *
313
     * This function is syntactically identical to
314
     * the regular PHP header() function, but is integrated into the framework. Every
315
     * Header you sent must go through this function or it might be lost later on;
316
     * this is especially important with caching.
317
     *
318
     * @param string $header    The header to send.
319
     * @param integer $response_code HTTP response code to send with the header
320
     */
321 17
    public function header($header, $response_code = null)
322
    {
323 17
        $this->cache->content->register_sent_header($header);
324 17
        midcom_compat_environment::get()->header($header, true, $response_code);
325 17
    }
326
327
    /**
328
     * Relocate to another URL.
329
     *
330
     * The helper actually can distinguish between site-local, absolute redirects and external
331
     * redirects. If the url does not start with http[s] or /, it is taken as a URL relative to
332
     * the current anchor prefix, which gets prepended automatically (no other characters
333
     * as the anchor prefix get inserted).
334
     *
335
     * Fully qualified urls (starting with http[s]) are used as-is.
336
     *
337
     * Note, that this function automatically makes the page uncacheable, calls
338
     * midcom_finish and exit, so it will never return. If the headers have already
339
     * been sent, this will leave you with a partially completed page, so beware.
340
     *
341
     * @param string $url    The URL to redirect to, will be preprocessed as outlined above.
342
     * @param int $response_code HTTP response code to send with the relocation, from 3xx series
343
     */
344
    public function relocate($url, $response_code = 302)
345
    {
346
        $response = new midcom_response_relocate($url, $response_code);
347
        $response->send();
348
        $this->finish();
349
    }
350
351
    /**
352
     * Raise some PHP limits for resource-intensive tasks
353
     */
354 8
    public function disable_limits()
355
    {
356 8
        $stat = @ini_set('max_execution_time', $this->config->get('midcom_max_execution_time'));
357 8
        if (false === $stat) {
358
            debug_add('ini_set("max_execution_time", ' . $this->config->get('midcom_max_execution_time') . ') returned false', MIDCOM_LOG_WARN);
359
        }
360 8
        $stat = @ini_set('memory_limit', $this->config->get('midcom_max_memory'));
361 8
        if (false === $stat) {
362
            debug_add('ini_set("memory_limit", ' . $this->config->get('midcom_max_memory') . ') returned false', MIDCOM_LOG_WARN);
363
        }
364 8
    }
365
}
366