Passed
Pull Request — master (#1197)
by Osma
03:50
created

WebController   F

Complexity

Total Complexity 89

Size/Duplication

Total Lines 622
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
eloc 339
dl 0
loc 622
rs 2
c 4
b 0
f 1
wmc 89

18 Methods

Rating   Name   Duplication   Size   Complexity  
A invokeVocabularyConcept() 0 31 5
C sendFeedback() 0 38 10
A createFeedbackHeaders() 0 12 3
B invokeFeedbackForm() 0 31 6
A __construct() 0 49 5
B listStyle() 0 10 8
B guessLanguage() 0 30 8
A invokeVocabularies() 0 21 1
A invokeAboutPage() 0 11 1
A invokeGroupIndex() 0 13 1
B invokeChangeList() 0 18 7
C invokeGlobalSearch() 0 75 12
B invokeVocabularySearch() 0 64 7
A getChangeList() 0 6 1
B invokeAlphabeticalIndex() 0 39 9
A invokeGenericErrorPage() 0 12 1
A formatChangeList() 0 8 2
A invokeVocabularyHome() 0 25 2

How to fix   Complexity   

Complex Class

Complex classes like WebController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WebController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Importing the dependencies.
5
 */
6
use \Punic\Language;
7
8
/**
9
 * WebController is an extension of the Controller that handles all
10
 * the requests originating from the view of the website.
11
 */
12
class WebController extends Controller
13
{
14
    /**
15
     * Provides access to the templating engine.
16
     * @property object $twig the twig templating engine.
17
     */
18
    public $twig;
19
    public $honeypot;
20
21
    /**
22
     * Constructor for the WebController.
23
     * @param Model $model
24
     */
25
    public function __construct($model)
26
    {
27
        parent::__construct($model);
28
29
        // initialize Twig templates
30
        $tmpDir = $model->getConfig()->getTemplateCache();
31
32
        // check if the cache pointed by config.ttl exists, if not we create it.
33
        if (!file_exists($tmpDir)) {
34
            mkdir($tmpDir);
35
        }
36
37
        // specify where to look for templates and cache
38
        $loader = new Twig_Loader_Filesystem('view');
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Loader_Filesystem has been deprecated: since Twig 2.7, use "Twig\Loader\FilesystemLoader" instead ( Ignorable by Annotation )

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

38
        $loader = /** @scrutinizer ignore-deprecated */ new Twig_Loader_Filesystem('view');
Loading history...
39
        // initialize Twig environment
40
        $this->twig = new Twig_Environment($loader, array('cache' => $tmpDir,'auto_reload' => true));
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Environment has been deprecated: since Twig 2.7, use "Twig\Environment" instead ( Ignorable by Annotation )

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

40
        $this->twig = /** @scrutinizer ignore-deprecated */ new Twig_Environment($loader, array('cache' => $tmpDir,'auto_reload' => true));
Loading history...
41
        $this->twig->addExtension(new Twig_Extensions_Extension_I18n());
42
        // used for setting the base href for the relative urls
43
        $this->twig->addGlobal("BaseHref", $this->getBaseHref());
44
        // setting the service name string from the config.ttl
45
        $this->twig->addGlobal("ServiceName", $this->model->getConfig()->getServiceName());
46
47
        // setting the service custom css file from the config.ttl
48
        if ($this->model->getConfig()->getCustomCss() !== null) {
0 ignored issues
show
introduced by
The condition $this->model->getConfig(...getCustomCss() !== null is always true.
Loading history...
49
            $this->twig->addGlobal("ServiceCustomCss", $this->model->getConfig()->getCustomCss());
50
        }
51
        // used for displaying the ui language selection as a dropdown
52
        if ($this->model->getConfig()->getUiLanguageDropdown() !== null) {
0 ignored issues
show
introduced by
The condition $this->model->getConfig(...uageDropdown() !== null is always true.
Loading history...
53
            $this->twig->addGlobal("LanguageDropdown", $this->model->getConfig()->getUiLanguageDropdown());
54
        }
55
56
        // setting the list of properties to be displayed in the search results
57
        $this->twig->addGlobal("PreferredProperties", array('skos:prefLabel', 'skos:narrower', 'skos:broader', 'skosmos:memberOf', 'skos:altLabel', 'skos:related'));
58
59
        // register a Twig filter for generating URLs for vocabulary resources (concepts and groups)
60
        $this->twig->addFilter(new Twig_SimpleFilter('link_url', array($this, 'linkUrlFilter')));
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFilter has been deprecated: since Twig 2.7, use "Twig\TwigFilter" instead ( Ignorable by Annotation )

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

60
        $this->twig->addFilter(/** @scrutinizer ignore-deprecated */ new Twig_SimpleFilter('link_url', array($this, 'linkUrlFilter')));
Loading history...
61
62
        // register a Twig filter for generating strings from language codes with CLDR
63
        $langFilter = new Twig_SimpleFilter('lang_name', function ($langcode, $lang) {
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFilter has been deprecated: since Twig 2.7, use "Twig\TwigFilter" instead ( Ignorable by Annotation )

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

63
        $langFilter = /** @scrutinizer ignore-deprecated */ new Twig_SimpleFilter('lang_name', function ($langcode, $lang) {
Loading history...
64
            return Language::getName($langcode, $lang);
65
        });
66
        $this->twig->addFilter($langFilter);
67
68
        // create the honeypot
69
        $this->honeypot = new \Honeypot();
70
        if (!$this->model->getConfig()->getHoneypotEnabled()) {
71
            $this->honeypot->disable();
72
        }
73
        $this->twig->addGlobal('honeypot', $this->honeypot);
74
    }
75
76
    /**
77
     * Guess the language of the user. Return a language string that is one
78
     * of the supported languages defined in the $LANGUAGES setting, e.g. "fi".
79
     * @param string $vocid identifier for the vocabulary eg. 'yso'.
80
     * @return string returns the language choice as a numeric string value
81
     */
82
    public function guessLanguage($vocid = null)
83
    {
84
        // 1. select language based on SKOSMOS_LANGUAGE cookie
85
        if (filter_input(INPUT_COOKIE, 'SKOSMOS_LANGUAGE', FILTER_SANITIZE_STRING)) {
86
            return filter_input(INPUT_COOKIE, 'SKOSMOS_LANGUAGE', FILTER_SANITIZE_STRING);
87
        }
88
89
        // 2. if vocabulary given, select based on the default language of the vocabulary
90
        if ($vocid !== null && $vocid !== '') {
91
            try {
92
                $vocab = $this->model->getVocabulary($vocid);
93
                return $vocab->getConfig()->getDefaultLanguage();
94
            } catch (Exception $e) {
95
                // vocabulary id not found, move on to the next selection method
96
            }
97
        }
98
99
        // 3. select language based on Accept-Language header
100
        header('Vary: Accept-Language'); // inform caches that a decision was made based on Accept header
101
        $this->negotiator = new \Negotiation\LanguageNegotiator();
0 ignored issues
show
Bug introduced by
The type Negotiation\LanguageNegotiator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
102
        $langcodes = array_keys($this->languages);
103
        // using a random language from the configured UI languages when there is no accept language header set
104
        $acceptLanguage = filter_input(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE', FILTER_SANITIZE_STRING) ? filter_input(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE', FILTER_SANITIZE_STRING) : $langcodes[0];
105
        $bestLang = $this->negotiator->getBest($acceptLanguage, $langcodes);
106
        if (isset($bestLang) && in_array($bestLang, $langcodes)) {
107
            return $bestLang->getValue();
108
        }
109
110
        // show default site or prompt for language
111
        return $langcodes[0];
112
    }
113
114
    /**
115
     * Determines a css class that controls width and positioning of the vocabulary list element.
116
     * The layout is wider if the left/right box templates have not been provided.
117
     * @return string css class for the container eg. 'voclist-wide' or 'voclist-right'
118
     */
119
    private function listStyle() {
120
        $left = file_exists('view/left.inc');
121
        $right = file_exists('view/right.inc');
122
        $ret = 'voclist';
123
        if (!$left && !$right) {
124
            $ret .= '-wide';
125
        } else if (!($left && $right) && ($right || $left)) {
126
            $ret .= ($right) ? '-left' : '-right';
127
        }
128
        return $ret;
129
    }
130
131
    /**
132
     * Loads and renders the view containing all the vocabularies.
133
     * @param Request $request
134
     */
135
    public function invokeVocabularies($request)
136
    {
137
        // set language parameters for gettext
138
        $this->setLanguageProperties($request->getLang());
139
        // load template
140
        $template = $this->twig->loadTemplate('light.twig');
141
        // set template variables
142
        $categoryLabel = $this->model->getClassificationLabel($request->getLang());
143
        $sortedVocabs = $this->model->getVocabularyList(false, true);
144
        $langList = $this->model->getLanguages($request->getLang());
145
        $listStyle = $this->listStyle();
146
147
        // render template
148
        echo $template->render(
149
            array(
150
                'sorted_vocabs' => $sortedVocabs,
151
                'category_label' => $categoryLabel,
152
                'languages' => $this->languages,
153
                'lang_list' => $langList,
154
                'request' => $request,
155
                'list_style' => $listStyle
156
            ));
157
    }
158
159
    /**
160
     * Invokes the concept page of a single concept in a specific vocabulary.
161
     *
162
     * @param Request $request
163
     */
164
    public function invokeVocabularyConcept(Request $request)
165
    {
166
        $lang = $request->getLang();
167
        $this->setLanguageProperties($lang);
168
        $vocab = $request->getVocab();
169
170
        $langcodes = $vocab->getConfig()->getShowLangCodes();
171
        $uri = $vocab->getConceptURI($request->getUri()); // make sure it's a full URI
172
173
        $results = $vocab->getConceptInfo($uri, $request->getContentLang());
174
        if (!$results) {
0 ignored issues
show
introduced by
$results is a non-empty array, thus ! $results is always false.
Loading history...
Bug Best Practice introduced by
The expression $results of type Concept[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
175
            $this->invokeGenericErrorPage($request);
176
            return;
177
        }
178
        if ($this->notModified($results[0])) {
179
            return;
180
        }
181
        $pluginParameters = $vocab->getConfig()->getPluginParameters();
182
        $template = (in_array('skos:Concept', $results[0]->getType()) || in_array('skos:ConceptScheme', $results[0]->getType())) ? $this->twig->loadTemplate('concept-info.twig') : $this->twig->loadTemplate('group-contents.twig');
183
184
        $crumbs = $vocab->getBreadCrumbs($request->getContentLang(), $uri);
185
        echo $template->render(array(
186
            'search_results' => $results,
187
            'vocab' => $vocab,
188
            'concept_uri' => $uri,
189
            'languages' => $this->languages,
190
            'explicit_langcodes' => $langcodes,
191
            'bread_crumbs' => $crumbs['breadcrumbs'],
192
            'combined' => $crumbs['combined'],
193
            'request' => $request,
194
            'plugin_params' => $pluginParameters)
195
        );
196
    }
197
198
    /**
199
     * Invokes the feedback page with information of the users current vocabulary.
200
     */
201
    public function invokeFeedbackForm($request)
202
    {
203
        $template = $this->twig->loadTemplate('feedback.twig');
204
        $this->setLanguageProperties($request->getLang());
205
        $vocabList = $this->model->getVocabularyList(false);
206
        $vocab = $request->getVocab();
207
208
        $feedbackSent = false;
209
        if ($request->getQueryParamPOST('message')) {
210
            $feedbackSent = true;
211
            $feedbackMsg = $request->getQueryParamPOST('message');
212
            $feedbackName = $request->getQueryParamPOST('name');
213
            $feedbackEmail = $request->getQueryParamPOST('email');
214
            $msgSubject = $request->getQueryParamPOST('msgsubject');
215
            $feedbackVocab = $request->getQueryParamPOST('vocab');
216
            $feedbackVocabEmail = ($feedbackVocab !== null && $feedbackVocab !== '') ?
217
                $this->model->getVocabulary($feedbackVocab)->getConfig()->getFeedbackRecipient() : null;
218
            // if the hidden field has been set a value we have found a spam bot
219
            // and we do not actually send the message.
220
            if ($this->honeypot->validateHoneypot($request->getQueryParamPOST('item-description')) &&
221
                $this->honeypot->validateHoneytime($request->getQueryParamPOST('user-captcha'), $this->model->getConfig()->getHoneypotTime())) {
222
                $this->sendFeedback($request, $feedbackMsg, $msgSubject, $feedbackName, $feedbackEmail, $feedbackVocab, $feedbackVocabEmail);
223
            }
224
        }
225
        echo $template->render(
226
            array(
227
                'languages' => $this->languages,
228
                'vocab' => $vocab,
229
                'vocabList' => $vocabList,
230
                'feedback_sent' => $feedbackSent,
231
                'request' => $request,
232
            ));
233
    }
234
235
    private function createFeedbackHeaders($fromName, $fromEmail, $toMail, $sender)
236
    {
237
        $headers = "MIME-Version: 1.0" . "\r\n";
238
        $headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
239
        if (!empty($toMail)) {
240
            $headers .= "Cc: " . $this->model->getConfig()->getFeedbackAddress() . "\r\n";
241
        }
242
        if (!empty($fromEmail)) {
243
            $headers .= "Reply-To: $fromName <$fromEmail>\r\n";
244
        }
245
        $service = $this->model->getConfig()->getServiceName();
246
        return $headers . "From: $fromName via $service <$sender>";
247
    }
248
249
    /**
250
     * Sends the user entered message through the php's mailer.
251
     * @param string $message content given by user.
252
     * @param string $messageSubject subject line given by user.
253
     * @param string $fromName senders own name.
254
     * @param string $fromEmail senders email address.
255
     * @param string $fromVocab which vocabulary is the feedback related to.
256
     */
257
    public function sendFeedback($request, $message, $messageSubject, $fromName = null, $fromEmail = null, $fromVocab = null, $toMail = null)
258
    {
259
        $toAddress = ($toMail) ? $toMail : $this->model->getConfig()->getFeedbackAddress();
260
        $messageSubject = "[" . $this->model->getConfig()->getServiceName() . "] " . $messageSubject;
261
        if ($fromVocab !== null && $fromVocab !== '') {
262
            $message = 'Feedback from vocab: ' . strtoupper($fromVocab) . "<br />" . $message;
263
        }
264
        $envelopeSender = $this->model->getConfig()->getFeedbackEnvelopeSender();
265
        // determine the sender address of the message
266
        $sender = $this->model->getConfig()->getFeedbackSender();
267
        if (empty($sender)) $sender = $envelopeSender;
268
        if (empty($sender)) $sender = $this->model->getConfig()->getFeedbackAddress();
269
270
        // determine sender name - default to "anonymous user" if not given by user
271
        if (empty($fromName)) $fromName = "anonymous user";
272
        $headers = $this->createFeedbackHeaders($fromName, $fromEmail, $toMail, $sender);
273
        $params = empty($envelopeSender) ? '' : "-f $envelopeSender";
274
        // adding some information about the user for debugging purposes.
275
        $message = $message . "<br /><br /> Debugging information:"
276
            . "<br />Timestamp: " . date(DATE_RFC2822)
277
            . "<br />User agent: " . $request->getServerConstant('HTTP_USER_AGENT')
278
            . "<br />Referer: " . $request->getServerConstant('HTTP_REFERER');
279
280
        try {
281
            mail($toAddress, $messageSubject, $message, $headers, $params);
282
        } catch (Exception $e) {
283
            header("HTTP/1.0 404 Not Found");
284
            $template = $this->twig->loadTemplate('error-page.twig');
285
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
286
                error_log('Caught exception: ' . $e->getMessage());
287
            }
288
289
            echo $template->render(
290
                array(
291
                    'languages' => $this->languages,
292
                ));
293
294
            return;
295
        }
296
    }
297
298
    /**
299
     * Invokes the about page for the Skosmos service.
300
     */
301
    public function invokeAboutPage($request)
302
    {
303
        $template = $this->twig->loadTemplate('about.twig');
304
        $this->setLanguageProperties($request->getLang());
305
        $url = $request->getServerConstant('HTTP_HOST');
306
307
        echo $template->render(
308
            array(
309
                'languages' => $this->languages,
310
                'server_instance' => $url,
311
                'request' => $request,
312
            ));
313
    }
314
315
    /**
316
     * Invokes the search for concepts in all the available ontologies.
317
     */
318
    public function invokeGlobalSearch($request)
319
    {
320
        $lang = $request->getLang();
321
        $template = $this->twig->loadTemplate('vocab-search-listing.twig');
322
        $this->setLanguageProperties($lang);
323
324
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
325
326
        $vocabs = $request->getQueryParam('vocabs'); # optional
327
        // convert to vocids array to support multi-vocabulary search
328
        $vocids = ($vocabs !== null && $vocabs !== '') ? explode(' ', $vocabs) : null;
329
        $vocabObjects = array();
330
        if ($vocids) {
331
            foreach($vocids as $vocid) {
332
                try {
333
                    $vocabObjects[] = $this->model->getVocabulary($vocid);
334
                } catch (ValueError $e) {
335
                    // skip vocabularies not found in configuration
336
                    // please note that this may result in global search
337
                    // NB: should not happen in normal UI interaction
338
                }
339
            }
340
        }
341
        $parameters->setVocabularies($vocabObjects);
342
343
        $nondefaultEndpointVocs = array();
344
345
        if (sizeOf($vocabObjects) != 1) {
346
            // global search, either from all (sizeOf($vocabObjects) == 0) or from selected ones
347
            if (sizeOf($vocabObjects) == 0) {
348
                $vocabObjects = $this->model->getVocabularies();
349
            }
350
            $defaultEndpoint = $this->model->getConfig()->getDefaultEndpoint();
351
            foreach($vocabObjects as $voc) {
352
                if ($voc->getEndpoint() !== $defaultEndpoint) {
353
                    $nondefaultEndpointVocs[] = $voc;
354
                }
355
            }
356
        }
357
358
        $counts = null;
359
        $searchResults = null;
360
        $errored = false;
361
362
        try {
363
            $countAndResults = $this->model->searchConceptsAndInfo($parameters);
364
            $counts = $countAndResults['count'];
365
            $searchResults = $countAndResults['results'];
366
        } catch (Exception $e) {
367
            $errored = true;
368
            header("HTTP/1.0 500 Internal Server Error");
369
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
370
                error_log('Caught exception: ' . $e->getMessage());
371
            }
372
        }
373
        $vocabList = $this->model->getVocabularyList();
374
        $sortedVocabs = $this->model->getVocabularyList(false, true);
375
        $langList = $this->model->getLanguages($lang);
376
377
        echo $template->render(
378
            array(
379
                'search_count' => $counts,
380
                'languages' => $this->languages,
381
                'search_results' => $searchResults,
382
                'rest' => $parameters->getOffset()>0,
383
                'global_search' => true,
384
                'search_failed' => $errored,
385
                'skipped_vocabs' => $nondefaultEndpointVocs,
386
                'term' => $request->getQueryParamRaw('q'),
387
                'lang_list' => $langList,
388
                'vocabs' => str_replace(' ', '+', $vocabs),
389
                'vocab_list' => $vocabList,
390
                'sorted_vocabs' => $sortedVocabs,
391
                'request' => $request,
392
                'parameters' => $parameters
393
            ));
394
    }
395
396
    /**
397
     * Invokes the search for a single vocabs concepts.
398
     */
399
    public function invokeVocabularySearch($request)
400
    {
401
        $template = $this->twig->loadTemplate('vocab-search-listing.twig');
402
        $this->setLanguageProperties($request->getLang());
403
        $vocab = $request->getVocab();
404
        $searchResults = null;
405
        try {
406
            $vocabTypes = $this->model->getTypes($request->getVocabid(), $request->getLang());
407
        } catch (Exception $e) {
408
            header("HTTP/1.0 500 Internal Server Error");
409
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
410
                error_log('Caught exception: ' . $e->getMessage());
411
            }
412
413
            echo $template->render(
414
                array(
415
                    'languages' => $this->languages,
416
                    'vocab' => $vocab,
417
                    'request' => $request,
418
                    'search_results' => $searchResults
419
                ));
420
421
            return;
422
        }
423
424
        $langcodes = $vocab->getConfig()->getShowLangCodes();
425
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
426
427
        try {
428
            $countAndResults = $this->model->searchConceptsAndInfo($parameters);
429
            $counts = $countAndResults['count'];
430
            $searchResults = $countAndResults['results'];
431
        } catch (Exception $e) {
432
            header("HTTP/1.0 404 Not Found");
433
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
434
                error_log('Caught exception: ' . $e->getMessage());
435
            }
436
437
            echo $template->render(
438
                array(
439
                    'languages' => $this->languages,
440
                    'vocab' => $vocab,
441
                    'term' => $request->getQueryParam('q'),
442
                    'search_results' => $searchResults
443
                ));
444
            return;
445
        }
446
        echo $template->render(
447
            array(
448
                'languages' => $this->languages,
449
                'vocab' => $vocab,
450
                'search_results' => $searchResults,
451
                'search_count' => $counts,
452
                'rest' => $parameters->getOffset()>0,
453
                'limit_parent' => $parameters->getParentLimit(),
454
                'limit_type' =>  $request->getQueryParam('type') ? explode('+', $request->getQueryParam('type')) : null,
455
                'limit_group' => $parameters->getGroupLimit(),
456
                'limit_scheme' =>  $request->getQueryParam('scheme') ? explode('+', $request->getQueryParam('scheme')) : null,
457
                'group_index' => $vocab->listConceptGroups($request->getContentLang()),
458
                'parameters' => $parameters,
459
                'term' => $request->getQueryParamRaw('q'),
460
                'types' => $vocabTypes,
461
                'explicit_langcodes' => $langcodes,
462
                'request' => $request,
463
            ));
464
    }
465
466
    /**
467
     * Invokes the alphabetical listing for a specific vocabulary.
468
     */
469
    public function invokeAlphabeticalIndex($request)
470
    {
471
        $lang = $request->getLang();
472
        $this->setLanguageProperties($lang);
473
        $template = $this->twig->loadTemplate('alphabetical-index.twig');
474
        $vocab = $request->getVocab();
475
476
        $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
477
        if ($request->getQueryParam('limit')) {
478
            $count = $request->getQueryParam('limit');
479
        } else {
480
            $count = ($offset > 0) ? null : 250;
481
        }
482
483
        $contentLang = $request->getContentLang();
484
485
        $allAtOnce = $vocab->getConfig()->getAlphabeticalFull();
486
        if (!$allAtOnce) {
487
            $letters = $vocab->getAlphabet($contentLang);
488
            $letter = $request->getLetter();
489
            if ($letter === '' && isset($letters[0])) {
490
                $letter = $letters[0];
491
            }
492
            $searchResults = $vocab->searchConceptsAlphabetical($letter, $count, $offset, $contentLang);
493
        } else {
494
            $letters = null;
495
            $searchResults = $vocab->searchConceptsAlphabetical('*', null, null, $contentLang);
496
        }
497
498
        $request->setContentLang($contentLang);
499
500
        echo $template->render(
501
            array(
502
                'languages' => $this->languages,
503
                'vocab' => $vocab,
504
                'alpha_results' => $searchResults,
505
                'letters' => $letters,
506
                'all_letters' => $allAtOnce,
507
                'request' => $request,
508
            ));
509
    }
510
511
    /**
512
     * Invokes the vocabulary group index page template.
513
     * @param boolean $stats set to true to get vocabulary statistics visible.
514
     */
515
    public function invokeGroupIndex($request, $stats = false)
516
    {
517
        $lang = $request->getLang();
518
        $this->setLanguageProperties($lang);
519
        $template = $this->twig->loadTemplate('group-index.twig');
520
        $vocab = $request->getVocab();
521
522
        echo $template->render(
523
            array(
524
                'languages' => $this->languages,
525
                'stats' => $stats,
526
                'vocab' => $vocab,
527
                'request' => $request,
528
            ));
529
    }
530
531
    /**
532
     * Loads and renders the view containing a specific vocabulary.
533
     */
534
    public function invokeVocabularyHome($request)
535
    {
536
        $lang = $request->getLang();
537
        // set language parameters for gettext
538
        $this->setLanguageProperties($lang);
539
        $vocab = $request->getVocab();
540
541
        $defaultView = $vocab->getConfig()->getDefaultSidebarView();
542
        // load template
543
        if ($defaultView === 'groups') {
544
            $this->invokeGroupIndex($request, true);
545
            return;
546
        }
547
        $pluginParameters = $vocab->getConfig()->getPluginParameters();
548
549
        $template = $this->twig->loadTemplate('vocab.twig');
550
551
        echo $template->render(
552
            array(
553
                'languages' => $this->languages,
554
                'vocab' => $vocab,
555
                'search_letter' => 'A',
556
                'active_tab' => $defaultView,
557
                'request' => $request,
558
                'plugin_params' => $pluginParameters
559
            ));
560
    }
561
562
    /**
563
     * Invokes a very generic errorpage.
564
     */
565
    public function invokeGenericErrorPage($request, $message = null)
566
    {
567
        $this->setLanguageProperties($request->getLang());
568
        header("HTTP/1.0 404 Not Found");
569
        $template = $this->twig->loadTemplate('error-page.twig');
570
        echo $template->render(
571
            array(
572
                'languages' => $this->languages,
573
                'request' => $request,
574
                'vocab' => $request->getVocab(),
575
                'message' => $message,
576
                'requested_page' => filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_STRING),
577
            ));
578
    }
579
580
    /**
581
     * Loads and renders the view containing a list of recent changes in the vocabulary.
582
     * @param Request $request
583
     */
584
    public function invokeChangeList($request, $prop='dc:created')
585
    {
586
        $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
587
        $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200;
588
589
        $changeList = $this->getChangeList($request, $prop, $offset, $limit);
0 ignored issues
show
Bug introduced by
It seems like $limit can also be of type string; however, parameter $limit of WebController::getChangeList() does only seem to accept integer, 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

589
        $changeList = $this->getChangeList($request, $prop, $offset, /** @scrutinizer ignore-type */ $limit);
Loading history...
Bug introduced by
It seems like $offset can also be of type string; however, parameter $offset of WebController::getChangeList() does only seem to accept integer, 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

589
        $changeList = $this->getChangeList($request, $prop, /** @scrutinizer ignore-type */ $offset, $limit);
Loading history...
590
        $bydate = $this->formatChangeList($changeList, $request->getLang());
591
592
        // load template
593
        $template = $this->twig->loadTemplate('changes.twig');
594
595
        // render template
596
        echo $template->render(
597
            array(
598
                'vocab' => $request->getVocab(),
599
                'languages' => $this->languages,
600
                'request' => $request,
601
                'changeList' => $bydate)
602
            );
603
    }
604
    /**
605
     * Gets the list of newest concepts for a vocabulary according to timestamp indicated by a property
606
     * @param Request $request
607
     * @param string $prop the name of the property eg. 'dc:modified'.
608
     * @param int $offset starting index offset
609
     * @param int $limit maximum number of concepts to return
610
     * @return Array list of concepts
611
     */
612
    public function getChangeList($request, $prop, $offset=0, $limit=200)
613
    {
614
        // set language parameters for gettext
615
        $this->setLanguageProperties($request->getLang());
616
617
        return $request->getVocab()->getChangeList($prop, $request->getContentLang(), $offset, $limit);
618
    }
619
620
    /**
621
     * Formats the list of concepts as labels arranged by modification month
622
     * @param Array $changeList
623
     * @param string $lang the language for displaying dates in the change list
624
     * @return array list of concepts as labels by month
625
     */
626
    public function formatChangeList($changeList, $lang)
627
    {
628
        $formatByDate = array();
629
        foreach($changeList as $concept) {
630
            $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $lang);
631
            $formatByDate[Punic\Calendar::getMonthName($concept['date'], 'wide', $lang, true) . Punic\Calendar::format($concept['date'], ' y', $lang) ][strtolower($concept['prefLabel'])] = $concept;
632
        }
633
        return $formatByDate;
634
    }
635
636
}
637