Passed
Push — master ( 52d6d0...ade603 )
by Andreas
33:03
created

midcom_application::header()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
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 Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
15
use Symfony\Component\Config\FileLocator;
16
17
/**
18
 * Main controlling instance of the MidCOM Framework
19
 *
20
 * @property midcom_services_i18n $i18n
21
 * @property midcom_helper__componentloader $componentloader
22
 * @property midcom_services_dbclassloader $dbclassloader
23
 * @property midcom_helper__dbfactory $dbfactory
24
 * @property midcom_helper_head $head
25
 * @property midcom_helper__styleloader $style
26
 * @property midcom_services_auth $auth
27
 * @property midcom_services_permalinks $permalinks
28
 * @property midcom_services_toolbars $toolbars
29
 * @property midcom_services_uimessages $uimessages
30
 * @property midcom_services_metadata $metadata
31
 * @property midcom_services_rcs $rcs
32
 * @property midcom_services__sessioning $session
33
 * @property midcom_services_indexer $indexer
34
 * @property midcom_config $config
35
 * @property midcom_services_cache $cache
36
 * @property midcom\events\dispatcher $dispatcher
37
 * @property midcom_debug $debug
38
 * @package midcom
39
 */
40
class midcom_application extends Kernel
41
{
42
    /**
43
     * Host prefix cache to avoid computing it each time.
44
     *
45
     * @var string
46
     * @see get_host_prefix()
47
     */
48
    private $_cached_host_prefix = '';
49
50
    /**
51
     * Page prefix cache to avoid computing it each time.
52
     *
53
     * @var string
54
     * @see get_page_prefix()
55
     */
56
    private $_cached_page_prefix = '';
57
58
    /**
59
     * @var Request
60
     */
61
    private $request;
62
63
    /**
64
     * Set this variable to true during the handle phase of your component to
65
     * not show the site's style around the component output. This is mainly
66
     * targeted at XML output like RSS feeds and similar things. The output
67
     * handler of the site, excluding the style-init/-finish tags will be executed
68
     * immediately after the handle phase
69
     *
70
     * Changing this flag after the handle phase or for dynamically loaded
71
     * components won't change anything.
72
     *
73
     * @var boolean
74
     */
75
    public $skip_page_style = false;
76
77
    private $project_dir;
78
79 1
    public function __construct(string $environment, bool $debug)
80
    {
81 1
        midcom_compat_environment::initialize();
82 1
        $this->request = Request::createFromGlobals();
83 1
        parent::__construct($environment, $debug);
84 1
    }
85
86 1
    public function registerContainerConfiguration(LoaderInterface $loader)
87
    {
88
        $loader->load(function (ContainerBuilder $container) use ($loader) {
0 ignored issues
show
Unused Code introduced by
The import $loader is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
89 1
            $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/config'));
90 1
            $loader->load('services.yml');
91 1
            midcom_exception_handler::register();
92 1
        });
93 1
    }
94
95 1
    public function registerBundles()
96
    {
97 1
        return [];
98
    }
99
100 1
    public function getProjectDir()
101
    {
102 1
        if ($this->project_dir === null) {
103 1
            if (basename(dirname(__DIR__, 4)) === 'vendor') {
104
                // this is the case where we're installed as a dependency
105
                $this->project_dir = dirname(__DIR__, 5);
106
            } else {
107 1
                $this->project_dir = dirname(__DIR__, 2);
108
            }
109
        }
110 1
        return $this->project_dir;
111
    }
112
113
    /**
114
     * Magic getter for service loading
115
     */
116 738
    public function __get($key)
117
    {
118 738
        return midcom::get($key);
119
    }
120
121
    /**
122
     * Magic setter
123
     */
124
    public function __set($key, $value)
125
    {
126
        midcom::get()->$key = $value;
127
    }
128
129
    /* *************************************************************************
130
     * Control framework:
131
     * codeinit      - Handle the current request
132
     * dynamic_load   - Dynamically load and execute a URL
133
     * finish         - Cleanup Work
134
     */
135
136
    /**
137
     * Initialize the URL parser and process the request.
138
     *
139
     * This function must be called before any output starts.
140
     */
141
    public function codeinit()
142
    {
143
        $this->handle($this->request)->send();
144
    }
145
146
    /**
147
     * Dynamically execute a subrequest and insert its output in place of the
148
     * function call.
149
     *
150
     * It tries to load the component referenced with the URL $url and executes
151
     * it as if it was used as primary component.
152
     *
153
     * This is only possible if the system is in the Page-Style output phase. It
154
     * cannot be used within code-init or during the output phase of another
155
     * component.
156
     *
157
     * Example code, executed on a site's homepage, it will load the news listing from
158
     * the given URL and display it using a substyle of the node style that is assigned
159
     * to the loaded one:
160
     *
161
     * <code>
162
     * $blog = '/blog/latest/3/';
163
     * $substyle = 'homepage';
164
     * midcom::get()->dynamic_load("/midcom-substyle-{$substyle}/{$blog}");
165
     * </code>
166
     *
167
     * Results of dynamic_loads are cached with the system cache strategy
168
     *
169
     * @param string $url                The URL, relative to the Midgard Page, that is to be requested.
170
     */
171 16
    public function dynamic_load($url)
172
    {
173 16
        debug_add("Dynamic load of URL {$url}");
174 16
        $url = midcom_connection::get_url('prefix') . $url;
175
176
        // Determine new Context ID and set current context,
177
        // enter that context and prepare its data structure.
178 16
        $oldcontext = midcom_core_context::get();
179 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

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