Completed
Push — master ( 474902...a16483 )
by Andreas
17:23
created

midcom_application::get_host_name()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

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

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