Passed
Push — master ( aed474...822a0b )
by Andreas
56:11 queued 26:29
created

midcom_application   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Test Coverage

Coverage 67.78%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 75
c 7
b 0
f 0
dl 0
loc 298
ccs 61
cts 90
cp 0.6778
rs 10
wmc 27

15 Methods

Rating   Name   Duplication   Size   Complexity  
A header() 0 4 1
A codeinit() 0 3 1
A get_page_prefix() 0 8 2
A __construct() 0 5 1
A disable_limits() 0 9 3
A get_host_name() 0 3 1
A __set() 0 3 1
A registerContainerConfiguration() 0 4 1
A registerBundles() 0 3 1
A relocate() 0 5 1
A __get() 0 3 1
A get_host_prefix() 0 15 4
A dynamic_load() 0 42 5
A finish() 0 4 1
A getProjectDir() 0 11 3
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
14
/**
15
 * Main controlling instance of the MidCOM Framework
16
 *
17
 * @property midcom_services_i18n $i18n
18
 * @property midcom_helper__componentloader $componentloader
19
 * @property midcom_services_dbclassloader $dbclassloader
20
 * @property midcom_helper__dbfactory $dbfactory
21
 * @property midcom_helper_head $head
22
 * @property midcom_helper__styleloader $style
23
 * @property midcom_services_auth $auth
24
 * @property midcom_services_permalinks $permalinks
25
 * @property midcom_services_toolbars $toolbars
26
 * @property midcom_services_uimessages $uimessages
27
 * @property midcom_services_metadata $metadata
28
 * @property midcom_services_rcs $rcs
29
 * @property midcom_services__sessioning $session
30
 * @property midcom_services_indexer $indexer
31
 * @property midcom_config $config
32
 * @property midcom_services_cache $cache
33
 * @property midcom\events\dispatcher $dispatcher
34
 * @property midcom_debug $debug
35
 * @package midcom
36
 */
37
class midcom_application extends Kernel
38
{
39
    /**
40
     * Host prefix cache to avoid computing it each time.
41
     *
42
     * @var string
43
     * @see get_host_prefix()
44
     */
45
    private $_cached_host_prefix = '';
46
47
    /**
48
     * Page prefix cache to avoid computing it each time.
49
     *
50
     * @var string
51
     * @see get_page_prefix()
52
     */
53
    private $_cached_page_prefix = '';
54
55
    /**
56
     * @var Request
57
     */
58
    private $request;
59
60
    /**
61
     * Set this variable to true during the handle phase of your component to
62
     * not show the site's style around the component output. This is mainly
63
     * targeted at XML output like RSS feeds and similar things. The output
64
     * handler of the site, excluding the style-init/-finish tags will be executed
65
     * immediately after the handle phase
66
     *
67
     * Changing this flag after the handle phase or for dynamically loaded
68
     * components won't change anything.
69
     *
70
     * @var boolean
71
     */
72
    public $skip_page_style = false;
73
74
    private $project_dir;
75
76 1
    public function __construct(string $environment, bool $debug)
77
    {
78 1
        midcom_compat_environment::initialize();
79 1
        $this->request = Request::createFromGlobals();
80 1
        parent::__construct($environment, $debug);
81 1
    }
82
83 1
    public function registerContainerConfiguration(LoaderInterface $loader)
84
    {
85 1
        $loader->load(__DIR__ . '/config/services.yml');
86 1
        midcom_exception_handler::register();
87 1
    }
88
89 1
    public function registerBundles()
90
    {
91 1
        return [];
92
    }
93
94 1
    public function getProjectDir()
95
    {
96 1
        if ($this->project_dir === null) {
97 1
            if (basename(dirname(__DIR__, 4)) === 'vendor') {
98
                // this is the case where we're installed as a dependency
99
                $this->project_dir = dirname(__DIR__, 5);
100
            } else {
101 1
                $this->project_dir = dirname(__DIR__, 2);
102
            }
103
        }
104 1
        return $this->project_dir;
105
    }
106
107
    /**
108
     * Magic getter for service loading
109
     */
110 738
    public function __get($key)
111
    {
112 738
        return midcom::get($key);
113
    }
114
115
    /**
116
     * Magic setter
117
     */
118
    public function __set($key, $value)
119
    {
120
        midcom::get()->$key = $value;
121
    }
122
123
    /* *************************************************************************
124
     * Control framework:
125
     * codeinit      - Handle the current request
126
     * dynamic_load   - Dynamically load and execute a URL
127
     * finish         - Cleanup Work
128
     */
129
130
    /**
131
     * Initialize the URL parser and process the request.
132
     *
133
     * This function must be called before any output starts.
134
     */
135
    public function codeinit()
136
    {
137
        $this->handle($this->request)->send();
138
    }
139
140
    /**
141
     * Dynamically execute a subrequest and insert its output in place of the
142
     * function call.
143
     *
144
     * It tries to load the component referenced with the URL $url and executes
145
     * it as if it was used as primary component.
146
     *
147
     * This is only possible if the system is in the Page-Style output phase. It
148
     * cannot be used within code-init or during the output phase of another
149
     * component.
150
     *
151
     * Example code, executed on a site's homepage, it will load the news listing from
152
     * the given URL and display it using a substyle of the node style that is assigned
153
     * to the loaded one:
154
     *
155
     * <code>
156
     * $blog = '/blog/latest/3/';
157
     * $substyle = 'homepage';
158
     * midcom::get()->dynamic_load("/midcom-substyle-{$substyle}/{$blog}");
159
     * </code>
160
     *
161
     * Results of dynamic_loads are cached with the system cache strategy
162
     *
163
     * @param string $url                The URL, relative to the Midgard Page, that is to be requested.
164
     */
165 16
    public function dynamic_load($url)
166
    {
167 16
        debug_add("Dynamic load of URL {$url}");
168 16
        $url = midcom_connection::get_url('prefix') . $url;
169
170
        // Determine new Context ID and set current context,
171
        // enter that context and prepare its data structure.
172 16
        $oldcontext = midcom_core_context::get();
173 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

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