Passed
Pull Request — main (#1631)
by
unknown
08:25 queued 03:26
created

WebController::sendFeedback()   C

Complexity

Conditions 10
Paths 192

Size

Total Lines 45
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 45
rs 6.9
c 0
b 0
f 0
cc 10
nc 192
nop 7

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Importing the dependencies.
5
 */
6
use Punic\Language;
7
use Symfony\Bridge\Twig\Extension\TranslationExtension;
8
9
/**
10
 * WebController is an extension of the Controller that handles all
11
 * the requests originating from the view of the website.
12
 */
13
class WebController extends Controller
14
{
15
    /**
16
     * Provides access to the templating engine.
17
     * @property object $twig the twig templating engine.
18
     */
19
    public $twig;
20
    public $honeypot;
21
    public $translator;
22
23
    /**
24
     * Constructor for the WebController.
25
     * @param Model $model
26
     */
27
    public function __construct($model)
28
    {
29
        parent::__construct($model);
30
31
        // initialize Twig templates
32
        $tmpDir = $model->getConfig()->getTemplateCache();
33
34
        // check if the cache pointed by config.ttl exists, if not we create it.
35
        if (!file_exists($tmpDir)) {
36
            mkdir($tmpDir);
37
        }
38
39
        // specify where to look for templates and cache
40
        $loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/../view');
41
        // initialize Twig environment
42
        $this->twig = new \Twig\Environment($loader, array('cache' => $tmpDir,'auto_reload' => true));
43
        // used for setting the base href for the relative urls
44
        $this->twig->addGlobal("BaseHref", $this->getBaseHref());
45
        // setting the service name string from the config.ttl
46
        $this->twig->addGlobal("ServiceName", $this->model->getConfig()->getServiceName());
47
48
        // setting the service custom css file from the config.ttl
49
        if ($this->model->getConfig()->getCustomCss() !== null) {
0 ignored issues
show
introduced by
The condition $this->model->getConfig(...getCustomCss() !== null is always true.
Loading history...
50
            $this->twig->addGlobal("ServiceCustomCss", $this->model->getConfig()->getCustomCss());
51
        }
52
        // used for displaying the ui language selection as a dropdown
53
        if ($this->model->getConfig()->getUiLanguageDropdown() !== null) {
0 ignored issues
show
introduced by
The condition $this->model->getConfig(...uageDropdown() !== null is always true.
Loading history...
54
            $this->twig->addGlobal("LanguageDropdown", $this->model->getConfig()->getUiLanguageDropdown());
55
        }
56
57
        // setting the list of properties to be displayed in the search results
58
        $this->twig->addGlobal("PreferredProperties", array('skos:prefLabel', 'skos:narrower', 'skos:broader', 'skosmos:memberOf', 'skos:altLabel', 'skos:related'));
59
60
        // register a Twig filter for generating URLs for vocabulary resources (concepts and groups)
61
        $this->twig->addFilter(new \Twig\TwigFilter('link_url', array($this, 'linkUrlFilter')));
62
63
        // register a Twig filter for generating strings from language codes with CLDR
64
        $langFilter = new \Twig\TwigFilter('lang_name', function ($langcode, $lang) {
65
            return Language::getName($langcode, $lang);
66
        });
67
        $this->twig->addFilter($langFilter);
68
69
        $this->translator = $model->getTranslator();
70
        $this->twig->addExtension(new TranslationExtension($this->translator));
71
72
        // create the honeypot
73
        $this->honeypot = new \Honeypot();
74
        if (!$this->model->getConfig()->getHoneypotEnabled()) {
75
            $this->honeypot->disable();
76
        }
77
        $this->twig->addGlobal('honeypot', $this->honeypot);
78
    }
79
80
    /**
81
     * Guess the language of the user. Return a language string that is one
82
     * of the supported languages defined in the $LANGUAGES setting, e.g. "fi".
83
     * @param Request $request HTTP request
84
     * @param string $vocid identifier for the vocabulary eg. 'yso'.
85
     * @return string returns the language choice as a numeric string value
86
     */
87
    public function guessLanguage($request, $vocid = null)
88
    {
89
        // 1. select language based on SKOSMOS_LANGUAGE cookie
90
        $languageCookie = $request->getCookie('SKOSMOS_LANGUAGE');
91
        if ($languageCookie) {
92
            return $languageCookie;
93
        }
94
95
        // 2. if vocabulary given, select based on the default language of the vocabulary
96
        if ($vocid !== null && $vocid !== '') {
97
            try {
98
                $vocab = $this->model->getVocabulary($vocid);
99
                return $vocab->getConfig()->getDefaultLanguage();
100
            } catch (Exception $e) {
101
                // vocabulary id not found, move on to the next selection method
102
            }
103
        }
104
105
        // 3. select language based on Accept-Language header
106
        header('Vary: Accept-Language'); // inform caches that a decision was made based on Accept header
107
        $this->negotiator = new \Negotiation\LanguageNegotiator();
108
        $langcodes = array_keys($this->languages);
109
        // using a random language from the configured UI languages when there is no accept language header set
110
        $acceptLanguage = $request->getServerConstant('HTTP_ACCEPT_LANGUAGE') ? $request->getServerConstant('HTTP_ACCEPT_LANGUAGE') : $langcodes[0];
111
112
        $bestLang = $this->negotiator->getBest($acceptLanguage, $langcodes);
113
        if (isset($bestLang) && in_array($bestLang->getValue(), $langcodes)) {
114
            return $bestLang->getValue();
115
        }
116
117
        // show default site or prompt for language
118
        return $langcodes[0];
119
    }
120
121
    /**
122
     * Determines a css class that controls width and positioning of the vocabulary list element.
123
     * The layout is wider if the left/right box templates have not been provided.
124
     * @return string css class for the container eg. 'voclist-wide' or 'voclist-right'
125
     */
126
    private function listStyle()
127
    {
128
        $left = file_exists('view/left.inc');
129
        $right = file_exists('view/right.inc');
130
        $ret = 'voclist';
131
        if (!$left && !$right) {
132
            $ret .= '-wide';
133
        } elseif (!($left && $right) && ($right || $left)) {
134
            $ret .= ($right) ? '-left' : '-right';
135
        }
136
        return $ret;
137
    }
138
139
    /**
140
     * Loads and renders the landing page view.
141
     * @param Request $request
142
     */
143
    public function invokeLandingPage($request)
144
    {
145
        $this->model->setLocale($request->getLang());
146
        // load template
147
        $template = $this->twig->load('landing.twig');
148
        // set template variables
149
        $categoryLabel = $this->model->getClassificationLabel($request->getLang());
150
        $sortedVocabs = $this->model->getVocabularyList(false, true);
151
        $langList = $this->model->getLanguages($request->getLang());
152
        $listStyle = $this->listStyle();
153
        $typeTranslations = $this->getConceptTypeTranslations($request);
154
155
        // render template
156
        echo $template->render(
157
            array(
158
                'sorted_vocabs' => $sortedVocabs,
159
                'category_label' => $categoryLabel,
160
                'languages' => $this->languages,
161
                'lang_list' => $langList,
162
                'request' => $request,
163
                'list_style' => $listStyle,
164
                'conceptTypeTranslations' => $typeTranslations,
165
            )
166
        );
167
    }
168
169
    /**
170
     * Invokes the concept page of a single concept in a specific vocabulary.
171
     *
172
     * @param Request $request
173
     */
174
    public function invokeVocabularyConcept(Request $request)
175
    {
176
        $lang = $request->getLang();
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
177
        $this->model->setLocale($request->getLang());
178
        $vocab = $request->getVocab();
179
180
        $langcodes = $vocab->getConfig()->getShowLangCodes();
181
        $uri = $vocab->getConceptURI($request->getUri()); // make sure it's a full URI
182
183
        $concept = $vocab->getConceptInfo($uri, $request->getContentLang());
184
        if (empty($concept)) {
185
            $this->invokeGenericErrorPage($request);
186
            return;
187
        }
188
        if ($this->notModified($concept)) {
189
            return;
190
        }
191
        $customLabels = $vocab->getConfig()->getPropertyLabelOverrides();
192
193
        $pluginParameters = json_encode($vocab->getConfig()->getPluginParameters());
194
        $template = $this->twig->load('concept.twig');
195
        $typeTranslations = $this->getConceptTypeTranslations($request);
196
197
        $crumbs = $vocab->getBreadCrumbs($request->getContentLang(), $uri);
198
        echo $template->render(
199
            array(
200
            'concept' => $concept,
201
            'vocab' => $vocab,
202
            'concept_uri' => $uri,
203
            'languages' => $this->languages,
204
            'explicit_langcodes' => $langcodes,
205
            'visible_breadcrumbs' => $crumbs['breadcrumbs'],
206
            'hidden_breadcrumbs' => $crumbs['combined'],
207
            'request' => $request,
208
            'plugin_params' => $pluginParameters,
209
            'custom_labels' => $customLabels,
210
            'conceptTypeTranslations' => $typeTranslations,
211
            )
212
        );
213
    }
214
215
    /**
216
     * Invokes the feedback page with information of the users current vocabulary.
217
     */
218
    public function invokeFeedbackForm($request)
219
    {
220
        $template = $this->twig->load('feedback.twig');
221
        $this->model->setLocale($request->getLang());
222
        $vocabList = $this->model->getVocabularyList(false);
223
        $vocab = $request->getVocab();
224
225
        $feedbackSent = false;
226
        if ($request->getQueryParamPOST('message')) {
227
            $feedbackSent = true;
228
            $feedbackMsg = $request->getQueryParamPOST('message');
229
            $feedbackName = $request->getQueryParamPOST('name');
230
            $feedbackEmail = $request->getQueryParamPOST('email');
231
            $msgSubject = $request->getQueryParamPOST('msgsubject');
232
            $feedbackVocab = $request->getQueryParamPOST('vocab');
233
            $feedbackVocabEmail = ($feedbackVocab !== null && $feedbackVocab !== '') ?
234
                $this->model->getVocabulary($feedbackVocab)->getConfig()->getFeedbackRecipient() : null;
235
            // if the hidden field has been set a value we have found a spam bot
236
            // and we do not actually send the message.
237
            if ($this->honeypot->validateHoneypot($request->getQueryParamPOST('item-description')) &&
238
                $this->honeypot->validateHoneytime($request->getQueryParamPOST('user-captcha'), $this->model->getConfig()->getHoneypotTime())) {
239
                $this->sendFeedback($request, $feedbackMsg, $msgSubject, $feedbackName, $feedbackEmail, $feedbackVocab, $feedbackVocabEmail);
240
            }
241
        }
242
        echo $template->render(
243
            array(
244
                'languages' => $this->languages,
245
                'vocab' => $vocab,
246
                'vocabList' => $vocabList,
247
                'feedback_sent' => $feedbackSent,
248
                'request' => $request,
249
            )
250
        );
251
    }
252
253
    private function createFeedbackHeaders($fromName, $fromEmail, $toMail, $sender)
254
    {
255
        $headers = "MIME-Version: 1.0" . "\r\n";
256
        $headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
257
        if (!empty($toMail)) {
258
            $headers .= "Cc: " . $this->model->getConfig()->getFeedbackAddress() . "\r\n";
259
        }
260
        if (!empty($fromEmail)) {
261
            $headers .= "Reply-To: $fromName <$fromEmail>\r\n";
262
        }
263
        $service = $this->model->getConfig()->getServiceName();
264
        return $headers . "From: $fromName via $service <$sender>";
265
    }
266
267
    /**
268
     * Sends the user entered message through the php's mailer.
269
     * @param string $message content given by user.
270
     * @param string $messageSubject subject line given by user.
271
     * @param string $fromName senders own name.
272
     * @param string $fromEmail senders email address.
273
     * @param string $fromVocab which vocabulary is the feedback related to.
274
     */
275
    public function sendFeedback($request, $message, $messageSubject, $fromName = null, $fromEmail = null, $fromVocab = null, $toMail = null)
276
    {
277
        $toAddress = ($toMail) ? $toMail : $this->model->getConfig()->getFeedbackAddress();
278
        $messageSubject = "[" . $this->model->getConfig()->getServiceName() . "] " . $messageSubject;
279
        if ($fromVocab !== null && $fromVocab !== '') {
280
            $message = 'Feedback from vocab: ' . strtoupper($fromVocab) . "<br />" . $message;
281
        }
282
        $envelopeSender = $this->model->getConfig()->getFeedbackEnvelopeSender();
283
        // determine the sender address of the message
284
        $sender = $this->model->getConfig()->getFeedbackSender();
285
        if (empty($sender)) {
286
            $sender = $envelopeSender;
287
        }
288
        if (empty($sender)) {
289
            $sender = $this->model->getConfig()->getFeedbackAddress();
290
        }
291
292
        // determine sender name - default to "anonymous user" if not given by user
293
        if (empty($fromName)) {
294
            $fromName = "anonymous user";
295
        }
296
        $headers = $this->createFeedbackHeaders($fromName, $fromEmail, $toMail, $sender);
297
        $params = empty($envelopeSender) ? '' : "-f $envelopeSender";
298
        // adding some information about the user for debugging purposes.
299
        $message = $message . "<br /><br /> Debugging information:"
300
            . "<br />Timestamp: " . date(DATE_RFC2822)
301
            . "<br />User agent: " . $request->getServerConstant('HTTP_USER_AGENT')
302
            . "<br />Referer: " . $request->getServerConstant('HTTP_REFERER');
303
304
        try {
305
            mail($toAddress, $messageSubject, $message, $headers, $params);
306
        } catch (Exception $e) {
307
            header("HTTP/1.0 404 Not Found");
308
            $template = $this->twig->load('error.twig');
309
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
310
                error_log('Caught exception: ' . $e->getMessage());
311
            }
312
313
            echo $template->render(
314
                array(
315
                    'languages' => $this->languages,
316
                )
317
            );
318
319
            return;
320
        }
321
    }
322
323
    /**
324
     * Invokes the about page for the Skosmos service.
325
     */
326
    public function invokeAboutPage($request)
327
    {
328
        $template = $this->twig->load('about.twig');
329
        $this->model->setLocale($request->getLang());
330
        $url = $request->getServerConstant('HTTP_HOST');
331
332
        echo $template->render(
333
            array(
334
                'languages' => $this->languages,
335
                'server_instance' => $url,
336
                'request' => $request,
337
            )
338
        );
339
    }
340
341
    /**
342
     * Invokes the search for concepts in all the available ontologies.
343
     */
344
    public function invokeGlobalSearch($request)
345
    {
346
        $lang = $request->getLang();
347
        $template = $this->twig->load('global-search.twig');
348
        $this->model->setLocale($request->getLang());
349
        $typeTranslations = $this->getConceptTypeTranslations($request);
350
        error_log('testataan');
351
        error_log($typeTranslations);
0 ignored issues
show
Bug introduced by
It seems like $typeTranslations can also be of type null; however, parameter $message of error_log() does only seem to accept string, 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

351
        error_log(/** @scrutinizer ignore-type */ $typeTranslations);
Loading history...
352
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
353
354
        $vocabs = $request->getQueryParam('vocabs'); # optional
355
        // convert to vocids array to support multi-vocabulary search
356
        $vocids = ($vocabs !== null && $vocabs !== '') ? explode(' ', $vocabs) : null;
357
        $vocabObjects = array();
358
        if ($vocids) {
359
            foreach($vocids as $vocid) {
360
                try {
361
                    $vocabObjects[] = $this->model->getVocabulary($vocid);
362
                } catch (ValueError $e) {
363
                    // fail fast with an error page if the vocabulary cannot be found
364
                    if ($this->model->getConfig()->getLogCaughtExceptions()) {
365
                        error_log('Caught exception: ' . $e->getMessage());
366
                    }
367
                    header("HTTP/1.0 400 Bad Request");
368
                    $this->invokeGenericErrorPage($request, $e->getMessage());
369
                    return;
370
                }
371
            }
372
        }
373
        $parameters->setVocabularies($vocabObjects);
374
375
        $counts = null;
376
        $searchResults = null;
377
        $errored = false;
378
379
        try {
380
            $countAndResults = $this->model->searchConceptsAndInfo($parameters);
381
            $counts = $countAndResults['count'];
382
            $searchResults = $countAndResults['results'];
383
        } catch (Exception $e) {
384
            $errored = true;
385
            header("HTTP/1.0 500 Internal Server Error");
386
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
387
                error_log('Caught exception: ' . $e->getMessage());
388
            }
389
        }
390
        $vocabList = $this->model->getVocabularyList();
391
        $sortedVocabs = $this->model->getVocabularyList(false, true);
392
        $langList = $this->model->getLanguages($lang);
393
394
        echo $template->render(
395
            array(
396
                'search_count' => $counts,
397
                'languages' => $this->languages,
398
                'search_results' => $searchResults,
399
                'rest' => $parameters->getOffset()>0,
400
                'global_search' => true,
401
                'search_failed' => $errored,
402
                'term' => $request->getQueryParamRaw('q'),
403
                'lang_list' => $langList,
404
                'vocabs' => str_replace(' ', '+', $vocabs),
405
                'vocab_list' => $vocabList,
406
                'sorted_vocabs' => $sortedVocabs,
407
                'request' => $request,
408
                'parameters' => $parameters,
409
                'conceptTypeTranslations' => $typeTranslations,
410
            )
411
        );
412
    }
413
414
    /**
415
     * Invokes the search for a single vocabs concepts.
416
     */
417
    public function invokeVocabularySearch($request)
418
    {
419
        $template = $this->twig->load('vocab-search.twig');
420
        $this->model->setLocale($request->getLang());
421
        $vocab = $request->getVocab();
422
        $searchResults = null;
423
        $typeTranslations = $this->getConceptTypeTranslations($request);
424
425
        try {
426
            $vocabTypes = $this->model->getTypes($request->getVocabid(), $request->getLang());
427
        } catch (Exception $e) {
428
            header("HTTP/1.0 500 Internal Server Error");
429
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
430
                error_log('Caught exception: ' . $e->getMessage());
431
            }
432
433
            echo $template->render(
434
                array(
435
                    'languages' => $this->languages,
436
                    'vocab' => $vocab,
437
                    'request' => $request,
438
                    'search_results' => $searchResults
439
                )
440
            );
441
442
            return;
443
        }
444
445
        $langcodes = $vocab->getConfig()->getShowLangCodes();
446
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
447
448
        try {
449
            $countAndResults = $this->model->searchConceptsAndInfo($parameters);
450
            $counts = $countAndResults['count'];
451
            $searchResults = $countAndResults['results'];
452
        } catch (Exception $e) {
453
            header("HTTP/1.0 404 Not Found");
454
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
455
                error_log('Caught exception: ' . $e->getMessage());
456
            }
457
458
            echo $template->render(
459
                array(
460
                    'languages' => $this->languages,
461
                    'vocab' => $vocab,
462
                    'term' => $request->getQueryParam('q'),
463
                    'search_results' => $searchResults
464
                )
465
            );
466
            return;
467
        }
468
        echo $template->render(
469
            array(
470
                'languages' => $this->languages,
471
                'vocab' => $vocab,
472
                'search_results' => $searchResults,
473
                'search_count' => $counts,
474
                'rest' => $parameters->getOffset()>0,
475
                'limit_parent' => $parameters->getParentLimit(),
476
                'limit_type' =>  $request->getQueryParam('type') ? explode('+', $request->getQueryParam('type')) : null,
477
                'limit_group' => $parameters->getGroupLimit(),
478
                'limit_scheme' =>  $request->getQueryParam('scheme') ? explode('+', $request->getQueryParam('scheme')) : null,
479
                'group_index' => $vocab->listConceptGroups($request->getContentLang()),
480
                'parameters' => $parameters,
481
                'term' => $request->getQueryParamRaw('q'),
482
                'types' => $vocabTypes,
483
                'explicit_langcodes' => $langcodes,
484
                'request' => $request,
485
                'conceptTypeTranslations' => $typeTranslations,
486
            )
487
        );
488
    }
489
490
    /**
491
     * Loads and renders the view containing a specific vocabulary.
492
     */
493
    public function invokeVocabularyHome($request)
494
    {
495
        $lang = $request->getLang();
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
496
        $this->model->setLocale($request->getLang());
497
        $vocab = $request->getVocab();
498
499
        $defaultView = $vocab->getConfig()->getDefaultSidebarView();
500
        // load template
501
        if ($defaultView === 'groups') {
502
            $this->invokeGroupIndex($request, true);
0 ignored issues
show
Bug introduced by
The method invokeGroupIndex() does not exist on WebController. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

502
            $this->/** @scrutinizer ignore-call */ 
503
                   invokeGroupIndex($request, true);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
503
            return;
504
        } elseif ($defaultView === 'new') {
505
            $this->invokeChangeList($request);
0 ignored issues
show
Bug introduced by
The method invokeChangeList() does not exist on WebController. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

505
            $this->/** @scrutinizer ignore-call */ 
506
                   invokeChangeList($request);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
506
        }
507
        $pluginParameters = json_encode($vocab->getConfig()->getPluginParameters());
508
509
        $template = $this->twig->load('vocab-home.twig');
510
        $typeTranslations = $this->getConceptTypeTranslations($request);
511
512
        echo $template->render(
513
            array(
514
                'languages' => $this->languages,
515
                'vocab' => $vocab,
516
                'search_letter' => 'A',
517
                'active_tab' => $defaultView,
518
                'request' => $request,
519
                'plugin_params' => $pluginParameters,
520
                'conceptTypeTranslations' => $typeTranslations,
521
            )
522
        );
523
    }
524
    /**
525
    * Get the translation strings to be displayed in the autocomplete search results
526
    */
527
    private function getConceptTypeTranslations($request)
528
    {
529
        $vocid = $request->getVocab() ? $request->getVocab()->getId() : null;
530
        if ($vocid === null && !$request->getLang()) {
531
            return $this->returnError(400, "Bad Request", "lang parameter missing");
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->returnError(400, ...ang parameter missing') targeting Controller::returnError() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
532
        }
533
        if ($this->notModified($request->getVocab())) {
534
            return null;
535
        }
536
537
        $this->model->setLocale($request->getLang());
538
        $queriedtypes = $this->model->getTypes($vocid, $request->getLang());
539
        $types = array();
540
541
        foreach ($queriedtypes as $uri => $typedata) {
542
            if ($typedata['label']) {
543
                $types[$uri] = $typedata['label'];
544
            }
545
        }
546
        return json_encode($types, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
547
    }
548
    /**
549
     * Invokes a very generic errorpage.
550
     */
551
    public function invokeGenericErrorPage($request, $message = null)
552
    {
553
        $this->model->setLocale($request->getLang());
554
        header("HTTP/1.0 404 Not Found");
555
        $template = $this->twig->load('error.twig');
556
        echo $template->render(
557
            array(
558
                'languages' => $this->languages,
559
                'request' => $request,
560
                'vocab' => $request->getVocab(),
561
                'message' => $message,
562
                'requested_page' => filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
0 ignored issues
show
Bug introduced by
The constant FILTER_SANITIZE_FULL_SPECIAL_CHARS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
563
            )
564
        );
565
    }
566
}
567