Completed
Push — master ( 3f43c2...c76c51 )
by
unknown
27s queued 20s
created

WebController::invokeFeedbackForm()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 16
nop 1
dl 0
loc 36
rs 8.7217
c 0
b 0
f 0
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');
39
        // initialize Twig environment
40
        $this->twig = new Twig_Environment($loader, array('cache' => $tmpDir,'auto_reload' => true));
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) {
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) {
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')));
61
62
        // register a Twig filter for generating strings from language codes with CLDR
63
        $langFilter = new Twig_SimpleFilter('lang_name', function ($langcode, $lang) {
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();
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
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
        /** @var \Twig\Template $template */
183
        $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');
184
185
        $crumbs = $vocab->getBreadCrumbs($request->getContentLang(), $uri);
186
        echo $template->render(array(
187
            'search_results' => $results,
188
            'vocab' => $vocab,
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
        $feedbackMsg = null;
210
        if ($request->getQueryParamPOST('message')) {
211
            $feedbackSent = true;
212
            $feedbackMsg = $request->getQueryParamPOST('message');
213
        }
214
        $feedbackName = $request->getQueryParamPOST('name');
215
        $feedbackEmail = $request->getQueryParamPOST('email');
216
        $feedbackVocab = $request->getQueryParamPOST('vocab');
217
218
        $feedbackVocabEmail = ($feedbackVocab !== null && $feedbackVocab !== '') ?
219
            $this->model->getVocabulary($feedbackVocab)->getConfig()->getFeedbackRecipient() : null;
220
221
        // if the hidden field has been set a value we have found a spam bot
222
        // and we do not actually send the message.
223
        if ($this->honeypot->validateHoneypot($request->getQueryParamPOST('item-description')) &&
224
            $this->honeypot->validateHoneytime($request->getQueryParamPOST('user-captcha'), $this->model->getConfig()->getHoneypotTime())) {
0 ignored issues
show
Documentation introduced by
$this->model->getConfig()->getHoneypotTime() is of type integer, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
225
            $this->sendFeedback($request, $feedbackMsg, $feedbackName, $feedbackEmail, $feedbackVocab, $feedbackVocabEmail);
226
        }
227
228
        echo $template->render(
229
            array(
230
                'languages' => $this->languages,
231
                'vocab' => $vocab,
232
                'vocabList' => $vocabList,
233
                'feedback_sent' => $feedbackSent,
234
                'request' => $request,
235
            ));
236
    }
237
238
    private function createFeedbackHeaders($fromName, $fromEmail, $toMail, $sender)
239
    {
240
        $headers = "MIME-Version: 1.0" . "\r\n";
241
        $headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
242
        if (!empty($toMail)) {
243
            $headers .= "Cc: " . $this->model->getConfig()->getFeedbackAddress() . "\r\n";
244
        }
245
        if (!empty($fromEmail)) {
246
            $headers .= "Reply-To: $fromName <$fromEmail>\r\n";
247
        }
248
249
        $service = $this->model->getConfig()->getServiceName();
250
        return $headers . "From: $fromName via $service <$sender>";
251
    }
252
253
    /**
254
     * Sends the user entered message through the php's mailer.
255
     * @param string $message only required parameter is the actual message.
256
     * @param string $fromName senders own name.
257
     * @param string $fromEmail senders email address.
258
     * @param string $fromVocab which vocabulary is the feedback related to.
259
     */
260
    public function sendFeedback($request, $message, $fromName = null, $fromEmail = null, $fromVocab = null, $toMail = null)
261
    {
262
        $toAddress = ($toMail) ? $toMail : $this->model->getConfig()->getFeedbackAddress();
263
        if ($fromVocab !== null && $fromVocab !== '') {
264
            $message = 'Feedback from vocab: ' . strtoupper($fromVocab) . "<br />" . $message;
265
        }
266
267
        $envelopeSender = $this->model->getConfig()->getFeedbackEnvelopeSender();
268
        $subject = $this->model->getConfig()->getServiceName() . " feedback";
269
        // determine the sender address of the message
270
        $sender = $this->model->getConfig()->getFeedbackSender();
271
        if (empty($sender)) $sender = $envelopeSender;
272
        if (empty($sender)) $sender = $this->model->getConfig()->getFeedbackAddress();
273
274
        // determine sender name - default to "anonymous user" if not given by user
275
        if (empty($fromName)) $fromName = "anonymous user";
276
277
        $headers = $this->createFeedbackHeaders($fromName, $fromEmail, $toMail, $sender);
278
        $params = empty($envelopeSender) ? '' : "-f $envelopeSender";
279
280
        // adding some information about the user for debugging purposes.
281
        $message = $message . "<br /><br /> Debugging information:"
282
            . "<br />Timestamp: " . date(DATE_RFC2822)
283
            . "<br />User agent: " . $request->getServerConstant('HTTP_USER_AGENT')
284
            . "<br />Referer: " . $request->getServerConstant('HTTP_REFERER');
285
286
        try {
287
            mail($toAddress, $subject, $message, $headers, $params);
288
        } catch (Exception $e) {
289
            header("HTTP/1.0 404 Not Found");
290
            $template = $this->twig->loadTemplate('error-page.twig');
291
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
292
                error_log('Caught exception: ' . $e->getMessage());
293
            }
294
295
            echo $template->render(
296
                array(
297
                    'languages' => $this->languages,
298
                ));
299
300
            return;
301
        }
302
    }
303
304
    /**
305
     * Invokes the about page for the Skosmos service.
306
     */
307 View Code Duplication
    public function invokeAboutPage($request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
308
    {
309
        $template = $this->twig->loadTemplate('about.twig');
310
        $this->setLanguageProperties($request->getLang());
311
        $url = $request->getServerConstant('HTTP_HOST');
312
        $version = $this->model->getVersion();
313
314
        echo $template->render(
315
            array(
316
                'languages' => $this->languages,
317
                'version' => $version,
318
                'server_instance' => $url,
319
                'request' => $request,
320
            ));
321
    }
322
323
    /**
324
     * Invokes the search for concepts in all the available ontologies.
325
     */
326
    public function invokeGlobalSearch($request)
327
    {
328
        $lang = $request->getLang();
329
        $template = $this->twig->loadTemplate('vocab-search-listing.twig');
330
        $this->setLanguageProperties($lang);
331
332
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
333
334
        $vocabs = $request->getQueryParam('vocabs'); # optional
335
        // convert to vocids array to support multi-vocabulary search
336
        $vocids = ($vocabs !== null && $vocabs !== '') ? explode(' ', $vocabs) : null;
337
        $vocabObjects = array();
338
        if ($vocids) {
339
            foreach($vocids as $vocid) {
340
                $vocabObjects[] = $this->model->getVocabulary($vocid);
341
            }
342
        }
343
        $parameters->setVocabularies($vocabObjects);
344
345
        try {
346
            $countAndResults = $this->model->searchConceptsAndInfo($parameters);
347
        } catch (Exception $e) {
348
            header("HTTP/1.0 404 Not Found");
349
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
350
                error_log('Caught exception: ' . $e->getMessage());
351
            }
352
            $this->invokeGenericErrorPage($request, $e->getMessage());
353
            return;
354
        }
355
        $counts = $countAndResults['count'];
356
        $searchResults = $countAndResults['results'];
357
        $vocabList = $this->model->getVocabularyList();
358
        $sortedVocabs = $this->model->getVocabularyList(false, true);
359
        $langList = $this->model->getLanguages($lang);
360
361
        echo $template->render(
362
            array(
363
                'search_count' => $counts,
364
                'languages' => $this->languages,
365
                'search_results' => $searchResults,
366
                'rest' => $parameters->getOffset()>0,
367
                'global_search' => true,
368
                'term' => $request->getQueryParamRaw('q'),
369
                'lang_list' => $langList,
370
                'vocabs' => str_replace(' ', '+', $vocabs),
371
                'vocab_list' => $vocabList,
372
                'sorted_vocabs' => $sortedVocabs,
373
                'request' => $request,
374
                'parameters' => $parameters
375
            ));
376
    }
377
378
    /**
379
     * Invokes the search for a single vocabs concepts.
380
     */
381
    public function invokeVocabularySearch($request)
382
    {
383
        $template = $this->twig->loadTemplate('vocab-search-listing.twig');
384
        $this->setLanguageProperties($request->getLang());
385
        $vocab = $request->getVocab();
386
        try {
387
            $vocabTypes = $this->model->getTypes($request->getVocabid(), $request->getLang());
388
        } catch (Exception $e) {
389
            header("HTTP/1.0 404 Not Found");
390
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
391
                error_log('Caught exception: ' . $e->getMessage());
392
            }
393
394
            echo $template->render(
395
                array(
396
                    'languages' => $this->languages,
397
                ));
398
399
            return;
400
        }
401
402
        $langcodes = $vocab->getConfig()->getShowLangCodes();
403
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
404
405
        try {
406
            $countAndResults = $this->model->searchConceptsAndInfo($parameters);
407
            $counts = $countAndResults['count'];
408
            $searchResults = $countAndResults['results'];
409
        } catch (Exception $e) {
410
            header("HTTP/1.0 404 Not Found");
411
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
412
                error_log('Caught exception: ' . $e->getMessage());
413
            }
414
415
            echo $template->render(
416
                array(
417
                    'languages' => $this->languages,
418
                    'vocab' => $vocab,
419
                    'term' => $request->getQueryParam('q'),
420
                ));
421
            return;
422
        }
423
        echo $template->render(
424
            array(
425
                'languages' => $this->languages,
426
                'vocab' => $vocab,
427
                'search_results' => $searchResults,
428
                'search_count' => $counts,
429
                'rest' => $parameters->getOffset()>0,
430
                'limit_parent' => $parameters->getParentLimit(),
431
                'limit_type' =>  $request->getQueryParam('type') ? explode('+', $request->getQueryParam('type')) : null,
432
                'limit_group' => $parameters->getGroupLimit(),
433
                'limit_scheme' =>  $request->getQueryParam('scheme') ? explode('+', $request->getQueryParam('scheme')) : null,
434
                'group_index' => $vocab->listConceptGroups($request->getContentLang()),
435
                'parameters' => $parameters,
436
                'term' => $request->getQueryParamRaw('q'),
437
                'types' => $vocabTypes,
438
                'explicit_langcodes' => $langcodes,
439
                'request' => $request,
440
            ));
441
    }
442
443
    /**
444
     * Invokes the alphabetical listing for a specific vocabulary.
445
     */
446
    public function invokeAlphabeticalIndex($request)
447
    {
448
        $lang = $request->getLang();
449
        $this->setLanguageProperties($lang);
450
        $template = $this->twig->loadTemplate('alphabetical-index.twig');
451
        $vocab = $request->getVocab();
452
453
        $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
454
        if ($request->getQueryParam('limit')) {
455
            $count = $request->getQueryParam('limit');
456
        } else {
457
            $count = ($offset > 0) ? null : 250;
458
        }
459
460
        $contentLang = $request->getContentLang();
461
462
        $allAtOnce = $vocab->getConfig()->getAlphabeticalFull();
463
        if (!$allAtOnce) {
464
            $letters = $vocab->getAlphabet($contentLang);
465
            $letter = $request->getLetter();
466
            if ($letter === '') {
467
                $letter = $letters[0];
468
            }
469
            $searchResults = $vocab->searchConceptsAlphabetical($letter, $count, $offset, $contentLang);
470
        } else {
471
            $letters = null;
472
            $searchResults = $vocab->searchConceptsAlphabetical('*', null, null, $contentLang);
473
        }
474
475
        $request->setContentLang($contentLang);
476
477
        echo $template->render(
478
            array(
479
                'languages' => $this->languages,
480
                'vocab' => $vocab,
481
                'alpha_results' => $searchResults,
482
                'letters' => $letters,
483
                'all_letters' => $allAtOnce,
484
                'request' => $request,
485
            ));
486
    }
487
488
    /**
489
     * Invokes the vocabulary group index page template.
490
     * @param boolean $stats set to true to get vocabulary statistics visible.
491
     */
492 View Code Duplication
    public function invokeGroupIndex($request, $stats = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
493
    {
494
        $lang = $request->getLang();
495
        $this->setLanguageProperties($lang);
496
        $template = $this->twig->loadTemplate('group-index.twig');
497
        $vocab = $request->getVocab();
498
499
        echo $template->render(
500
            array(
501
                'languages' => $this->languages,
502
                'stats' => $stats,
503
                'vocab' => $vocab,
504
                'request' => $request,
505
            ));
506
    }
507
508
    /**
509
     * Loads and renders the view containing a specific vocabulary.
510
     */
511
    public function invokeVocabularyHome($request)
512
    {
513
        $lang = $request->getLang();
514
        // set language parameters for gettext
515
        $this->setLanguageProperties($lang);
516
        $vocab = $request->getVocab();
517
518
        $defaultView = $vocab->getConfig()->getDefaultSidebarView();
519
        // load template
520
        if ($defaultView === 'groups') {
521
            $this->invokeGroupIndex($request, true);
522
            return;
523
        }
524
        $pluginParameters = $vocab->getConfig()->getPluginParameters();
525
526
        $template = $this->twig->loadTemplate('vocab.twig');
527
528
        echo $template->render(
529
            array(
530
                'languages' => $this->languages,
531
                'vocab' => $vocab,
532
                'search_letter' => 'A',
533
                'active_tab' => $defaultView,
534
                'request' => $request,
535
                'plugin_params' => $pluginParameters
536
            ));
537
    }
538
539
    /**
540
     * Invokes a very generic errorpage.
541
     */
542
    public function invokeGenericErrorPage($request, $message = null)
543
    {
544
        $this->setLanguageProperties($request->getLang());
545
        header("HTTP/1.0 404 Not Found");
546
        $template = $this->twig->loadTemplate('error-page.twig');
547
        echo $template->render(
548
            array(
549
                'languages' => $this->languages,
550
                'request' => $request,
551
                'message' => $message,
552
                'requested_page' => filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_STRING),
553
            ));
554
    }
555
556
    /**
557
     * Loads and renders the view containing a list of recent changes in the vocabulary.
558
     * @param Request $request
559
     */
560
    public function invokeChangeList($request, $prop='dc:created')
561
    {
562
        $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
563
        $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200;
564
565
        $changeList = $this->getChangeList($request, $prop, $offset, $limit);
566
        $bydate = $this->formatChangeList($changeList, $request->getLang());
567
568
        // load template
569
        $template = $this->twig->loadTemplate('changes.twig');
570
571
        // render template
572
        echo $template->render(
573
            array(
574
                'vocab' => $request->getVocab(),
575
                'languages' => $this->languages,
576
                'request' => $request,
577
                'changeList' => $bydate)
578
            );
579
    }
580
    /**
581
     * Gets the list of newest concepts for a vocabulary according to timestamp indicated by a property
582
     * @param Request $request
583
     * @param string $prop the name of the property eg. 'dc:modified'.
584
     * @param int $offset starting index offset
585
     * @param int $limit maximum number of concepts to return
586
     * @return Array list of concepts
587
     */
588
    public function getChangeList($request, $prop, $offset=0, $limit=200)
589
    {
590
        // set language parameters for gettext
591
        $this->setLanguageProperties($request->getLang());
592
593
        return $request->getVocab()->getChangeList($prop, $request->getContentLang(), $offset, $limit);
594
    }
595
596
    /**
597
    * Formats the list of concepts as labels arranged by modification month
598
    * @param Array $changeList
599
    * @param string $lang the language for displaying dates in the change list
600
    */
601
    public function formatChangeList($changeList, $lang)
602
    {
603
        $formatByDate = array();
604
        foreach($changeList as $concept) {
605
            $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $lang);
606
            $formatByDate[Punic\Calendar::getMonthName($concept['date'], 'wide', $lang, true) . Punic\Calendar::format($concept['date'], ' y', $lang) ][strtolower($concept['prefLabel'])] = $concept;
607
        }
608
        return $formatByDate;
609
    }
610
611
}
612