Passed
Push — master ( 942d5f...e1495e )
by Andreas
18:45
created

midcom_application::get_host_prefix()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.128

Importance

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

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

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