Completed
Branch master (8e2732)
by Osma
04:46 queued 01:55
created

WebController::guessBaseHref()   B

Complexity

Conditions 6
Paths 20

Size

Total Lines 18
Code Lines 16

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 18
rs 8.8571
cc 6
eloc 16
nc 20
nop 0
1
<?php
2
/**
3
 * Copyright (c) 2012-2013 Aalto University and University of Helsinki
4
 * MIT License
5
 * see LICENSE.txt for more information
6
 */
7
8
/**
9
 * Importing the dependencies.
10
 */
11
use \Punic\Language;
12
13
/**
14
 * WebController is an extension of the Controller that handles all
15
 * the requests originating from the view of the website.
16
 */
17
class WebController extends Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
18
{
19
    /**
20
     * Provides access to the templating engine.
21
     * @property object $twig the twig templating engine.
22
     */
23
    public $twig;
24
25
    /**
26
     * Constructor for the WebController.
27
     * @param Model $model
28
     */
29
    public function __construct($model)
30
    {
31
        parent::__construct($model);
32
33
        // initialize Twig templates
34
        $tmp_dir = $model->getConfig()->getTemplateCache();
35
36
        // check if the cache pointed by config.inc exists, if not we create it.
37
        if (!file_exists($tmp_dir)) {
38
            mkdir($tmp_dir);
39
        }
40
41
        // specify where to look for templates and cache
42
        $loader = new Twig_Loader_Filesystem('view');
43
        // initialize Twig environment
44
        $this->twig = new Twig_Environment($loader, array('cache' => $tmp_dir,
45
            'auto_reload' => true, 'debug' => true));
46
        $this->twig->addExtension(new Twig_Extensions_Extension_I18n());
47
        //ENABLES DUMP() method for easy and fun debugging!
48
        $this->twig->addExtension(new Twig_Extension_Debug());
49
        // used for setting the base href for the relative urls
50
        $this->twig->addGlobal("BaseHref", $this->getBaseHref());
51
        // setting the service name string from the config.inc
52
        $this->twig->addGlobal("ServiceName", $this->model->getConfig()->getServiceName());
53
        // setting the service logo location from the config.inc
54
        if ($this->model->getConfig()->getServiceLogo() !== null) {
55
            $this->twig->addGlobal("ServiceLogo", $this->model->getConfig()->getServiceLogo());
56
        }
57
58
        // setting the service custom css file from the config.inc
59
        if ($this->model->getConfig()->getCustomCss() !== null) {
60
            $this->twig->addGlobal("ServiceCustomCss", $this->model->getConfig()->getCustomCss());
61
        }
62
        // used for displaying the ui language selection as a dropdown
63
        if ($this->model->getConfig()->getUiLanguageDropdown() !== null) {
64
            $this->twig->addGlobal("LanguageDropdown", $this->model->getConfig()->getUiLanguageDropdown());
65
        }
66
67
        // setting the list of properties to be displayed in the search results
68
        $this->twig->addGlobal("PreferredProperties", array('skos:prefLabel', 'skos:narrower', 'skos:broader', 'skosmos:memberOf', 'skos:altLabel', 'skos:related'));
69
70
        // register a Twig filter for generating URLs for vocabulary resources (concepts and groups)
71
        $controller = $this; // for use by anonymous function below
72
        $urlFilter = new Twig_SimpleFilter('link_url', function ($uri, $vocab, $lang, $type = 'page', $clang = null, $term = null) use ($controller) {
73
            // $vocab can either be null, a vocabulary id (string) or a Vocabulary object
74
            if ($vocab === null) {
75
                // target vocabulary is unknown, best bet is to link to the plain URI
76
                return $uri;
77
            } elseif (is_string($vocab)) {
78
                $vocid = $vocab;
79
                $vocab = $controller->model->getVocabulary($vocid);
80
            } else {
81
                $vocid = $vocab->getId();
82
            }
83
84
            $params = array();
85
            if (isset($clang) && $clang !== $lang) {
86
                $params['clang'] = $clang;
87
            }
88
89
            if (isset($term)) {
90
                $params['q'] = $term;
91
            }
92
93
            // case 1: URI within vocabulary namespace: use only local name
94
            $localname = $vocab->getLocalName($uri);
95
            if ($localname !== $uri && $localname === urlencode($localname)) {
96
                // check that the prefix stripping worked, and there are no problematic chars in localname
97
                $paramstr = sizeof($params) > 0 ? '?' . http_build_query($params) : '';
98
                if ($type && $type !== '' && $type !== 'vocab') {
99
                    return "$vocid/$lang/$type/$localname" . $paramstr;
100
                }
101
102
                return "$vocid/$lang/$localname" . $paramstr;
103
            }
104
105
            // case 2: URI outside vocabulary namespace, or has problematic chars
106
            // pass the full URI as parameter instead
107
            $params['uri'] = $uri;
108
            return "$vocid/$lang/$type/?" . http_build_query($params);
109
        });
110
        $this->twig->addFilter($urlFilter);
111
112
        // register a Twig filter for generating strings from language codes with CLDR
113
        $langFilter = new Twig_SimpleFilter('lang_name', function ($langcode, $lang) {
114
            return Language::getName($langcode, $lang);
115
        });
116
        $this->twig->addFilter($langFilter);
117
118
    }
119
120
    /**
121
     * Guess the language of the user. Return a language string that is one
122
     * of the supported languages defined in the $LANGUAGES setting, e.g. "fi".
123
     * @param string $vocab_id identifier for the vocabulary eg. 'yso'.
124
     * @return string returns the language choice as a numeric string value
125
     */
126
    public function guessLanguage($vocab_id = null)
127
    {
128
        // 1. select language based on SKOSMOS_LANGUAGE cookie
129
        if (filter_input(INPUT_COOKIE, 'SKOSMOS_LANGUAGE', FILTER_SANITIZE_STRING)) {
130
            return filter_input(INPUT_COOKIE, 'SKOSMOS_LANGUAGE', FILTER_SANITIZE_STRING);
131
        }
132
133
        // 2. if vocabulary given, select based on the default language of the vocabulary
134
        if ($vocab_id !== null && $vocab_id !== '') {
135
            try {
136
                $vocab = $this->model->getVocabulary($vocab_id);
137
                return $vocab->getConfig()->getDefaultLanguage();
138
            } catch (Exception $e) {
139
                // vocabulary id not found, move on to the next selection method
140
            }
141
        }
142
143
        // 3. select language based on Accept-Language header
144
        header('Vary: Accept-Language'); // inform caches that a decision was made based on Accept header
145
        $this->negotiator = new \Negotiation\LanguageNegotiator();
146
        $langcodes = array_keys($this->languages);
147
        $acceptLanguage = filter_input(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE', FILTER_SANITIZE_STRING) ? filter_input(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE', FILTER_SANITIZE_STRING) : '';
148
        $bestLang = $this->negotiator->getBest($acceptLanguage, $langcodes);
149
        if (isset($bestLang) && in_array($bestLang, $langcodes)) {
150
            return $bestLang->getValue();
151
        }
152
153
        // show default site or prompt for language
154
        return $langcodes[0];
155
    }
156
157
    /**
158
     * Loads and renders the view containing all the vocabularies.
159
     * @param Request $request
160
     */
161
    public function invokeVocabularies($request)
162
    {
163
        // set language parameters for gettext
164
        $this->setLanguageProperties($request->getLang());
165
        // load template
166
        $template = $this->twig->loadTemplate('light.twig');
167
        // set template variables
168
        $categoryLabel = $this->model->getClassificationLabel($request->getLang());
169
        $sortedVocabs = $this->model->getVocabularyList(false, true);
170
        $langList = $this->model->getLanguages($request->getLang());
171
172
        // render template
173
        echo $template->render(
174
            array(
175
                'sorted_vocabs' => $sortedVocabs,
176
                'category_label' => $categoryLabel,
177
                'languages' => $this->languages,
178
                'lang_list' => $langList,
179
                'request' => $request,
180
            ));
181
    }
182
183
    /**
184
     * Invokes the concept page of a single concept in a specific vocabulary.
185
     */
186
    public function invokeVocabularyConcept($request)
187
    {
188
        $lang = $request->getLang();
189
        $this->setLanguageProperties($lang);
190
        $vocab = $request->getVocab();
191
192
        $langcodes = $vocab->getConfig()->getShowLangCodes();
193
        $uri = $vocab->getConceptURI($request->getUri()); // make sure it's a full URI
194
195
        $results = $vocab->getConceptInfo($uri, $request->getContentLang());
196
        if (!$results) {
197
            $this->invokeGenericErrorPage($request);
198
            return;
199
        }
200
        $template = (in_array('skos:Concept', $results[0]->getType())) ? $this->twig->loadTemplate('concept-info.twig') : $this->twig->loadTemplate('group-contents.twig');
201
        
202
        $crumbs = $vocab->getBreadCrumbs($request->getContentLang(), $uri);
203
        echo $template->render(array(
204
            'search_results' => $results,
205
            'vocab' => $vocab,
206
            'languages' => $this->languages,
207
            'explicit_langcodes' => $langcodes,
208
            'bread_crumbs' => $crumbs['breadcrumbs'],
209
            'combined' => $crumbs['combined'],
210
            'request' => $request)
211
        );
212
    }
213
214
    /**
215
     * Invokes the feedback page with information of the users current vocabulary.
216
     */
217
    public function invokeFeedbackForm($request)
218
    {
219
        $template = $this->twig->loadTemplate('feedback.twig');
220
        $this->setLanguageProperties($request->getLang());
221
        $vocabList = $this->model->getVocabularyList(false);
222
        $vocab = $request->getVocab();
223
224
        $feedback_sent = false;
225
        $feedback_msg = null;
226
        if (filter_input(INPUT_POST, 'message', FILTER_SANITIZE_STRING)) {
227
            $feedback_sent = true;
228
            $feedback_msg = filter_input(INPUT_POST, 'message', FILTER_SANITIZE_STRING);
229
        }
230
        $feedback_name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
231
        $feedback_email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING);
232
        $feedback_vocab = filter_input(INPUT_POST, 'vocab', FILTER_SANITIZE_STRING);
233
        $feedback_vocab_email = ($vocab !== null) ? $vocab->getConfig()->getFeedbackRecipient() : null;
234
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 ($feedback_sent && filter_input(INPUT_POST, 'trap', FILTER_SANITIZE_STRING) === '') {
238
            $this->sendFeedback($feedback_msg, $feedback_name, $feedback_email, $feedback_vocab, $feedback_vocab_email);
239
        }
240
241
        echo $template->render(
242
            array(
243
                'languages' => $this->languages,
244
                'vocab' => $vocab,
245
                'vocabList' => $vocabList,
246
                'feedback_sent' => $feedback_sent,
247
                'request' => $request,
248
            ));
249
    }
250
251
    /**
252
     * Sends the user entered message through the php's mailer.
253
     * @param string $message only required parameter is the actual message.
254
     * @param string $fromName senders own name.
255
     * @param string $fromEmail senders email adress.
256
     * @param string $fromVocab which vocabulary is the feedback related to.
257
     */
258
    public function sendFeedback($message, $fromName = null, $fromEmail = null, $fromVocab = null, $toMail = null)
259
    {
260
        $toAddress = ($toMail) ? $toMail : $this->model->getConfig()->getFeedbackAddress();
261
        if ($fromVocab !== null) {
262
            $message = 'Feedback from vocab: ' . strtoupper($fromVocab) . "<br />" . $message;
263
        }
264
265
        $subject = SERVICE_NAME . " feedback";
266
        $headers = "MIME-Version: 1.0″ . '\r\n";
267
        $headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
268
        if ($toMail) {
269
            $headers .= "Cc: " . $this->model->getConfig()->getFeedbackAddress() . "\r\n";
270
        }
271
272
        $headers .= "From: $fromName <$fromEmail>" . "\r\n" . 'X-Mailer: PHP/' . phpversion();
273
        $envelopeSender = FEEDBACK_ENVELOPE_SENDER;
274
        $params = empty($envelopeSender) ? '' : "-f $envelopeSender";
275
276
        // adding some information about the user for debugging purposes.
277
        $agent = (filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING)) ? filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING) : '';
278
        $referer = (filter_input(INPUT_SERVER, 'HTTP_REFERER', FILTER_SANITIZE_STRING)) ? filter_input(INPUT_SERVER, 'HTTP_REFERER', FILTER_SANITIZE_STRING) : '';
279
        $ipAddress = (filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING)) ? filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING) : '';
280
        $timestamp = date(DATE_RFC2822);
281
282
        $message = $message . "<br /><br /> Debugging information:"
283
            . "<br />Timestamp: " . $timestamp
284
            . "<br />User agent: " . $agent
285
            . "<br />IP address: " . $ipAddress
286
            . "<br />Referer: " . $referer;
287
288
        try {
289
            mail($toAddress, $subject, $message, $headers, $params);
290
        } catch (Exception $e) {
291
            header("HTTP/1.0 404 Not Found");
292
            $template = $this->twig->loadTemplate('error-page.twig');
293
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
294
                error_log('Caught exception: ' . $e->getMessage());
295
            }
296
297
            echo $template->render(
298
                array(
299
                    'languages' => $this->languages,
300
                ));
301
302
            return;
303
        }
304
    }
305
306
    /**
307
     * Invokes the about page for the Skosmos service.
308
     */
309 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...
310
    {
311
        $template = $this->twig->loadTemplate('about.twig');
312
        $this->setLanguageProperties($request->getLang());
313
        $url = $request->getServerConstant('HTTP_HOST');
314
        $version = $this->model->getVersion();
315
316
        echo $template->render(
317
            array(
318
                'languages' => $this->languages,
319
                'version' => $version,
320
                'server_instance' => $url,
321
                'request' => $request,
322
            ));
323
    }
324
325
    /**
326
     * Invokes the search for concepts in all the availible ontologies.
327
     */
328
    public function invokeGlobalSearch($request)
329
    {
330
        $lang = $request->getLang();
331
        $template = $this->twig->loadTemplate('vocab-search-listing.twig');
332
        $this->setLanguageProperties($lang);
333
334
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
335
336
        $vocabs = $request->getQueryParam('vocabs'); # optional
337
        // convert to vocids array to support multi-vocabulary search
338
        $vocids = ($vocabs !== null && $vocabs !== '') ? explode(' ', $vocabs) : null;
339
        $vocabObjects = array();
340
        if ($vocids) {
341
            foreach($vocids as $vocid) {
342
                $vocabObjects[] = $this->model->getVocabulary($vocid);
343
            }
344
        }
345
        $parameters->setVocabularies($vocabObjects);
346
347
        try {
348
            $count_and_results = $this->model->searchConceptsAndInfo($parameters);
349
        } catch (Exception $e) {
350
            header("HTTP/1.0 404 Not Found");
351
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
352
                error_log('Caught exception: ' . $e->getMessage());
353
            }
354
            $this->invokeGenericErrorPage($request, $e->getMessage());
355
            return;
356
        }
357
        $counts = $count_and_results['count'];
358
        $search_results = $count_and_results['results'];
359
        $vocabList = $this->model->getVocabularyList();
360
        $sortedVocabs = $this->model->getVocabularyList(false, true);
361
        $langList = $this->model->getLanguages($lang);
362
363
        echo $template->render(
364
            array(
365
                'search_count' => $counts,
366
                'languages' => $this->languages,
367
                'search_results' => $search_results,
368
                'rest' => $parameters->getOffset()>0,
369
                'global_search' => true,
370
                'term' => $request->getQueryParam('q'),
371
                'lang_list' => $langList,
372
                'vocabs' => str_replace(' ', '+', $vocabs),
373
                'vocab_list' => $vocabList,
374
                'sorted_vocabs' => $sortedVocabs,
375
                'request' => $request,
376
                'parameters' => $parameters
377
            ));
378
    }
379
380
    /**
381
     * Invokes the search for a single vocabs concepts.
382
     */
383
    public function invokeVocabularySearch($request)
384
    {
385
        $template = $this->twig->loadTemplate('vocab-search-listing.twig');
386
        $this->setLanguageProperties($request->getLang());
387
        $vocab = $request->getVocab();
388
        try {
389
            $vocab_types = $this->model->getTypes($request->getVocabid(), $request->getLang());
390
        } catch (Exception $e) {
391
            header("HTTP/1.0 404 Not Found");
392
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
393
                error_log('Caught exception: ' . $e->getMessage());
394
            }
395
396
            echo $template->render(
397
                array(
398
                    'languages' => $this->languages,
399
                ));
400
401
            return;
402
        }
403
404
        $langcodes = $vocab->getConfig()->getShowLangCodes();
405
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig());
406
407
        try {
408
            $count_and_results = $this->model->searchConceptsAndInfo($parameters);
409
            $counts = $count_and_results['count'];
410
            $search_results = $count_and_results['results'];
411
        } catch (Exception $e) {
412
            header("HTTP/1.0 404 Not Found");
413
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
414
                error_log('Caught exception: ' . $e->getMessage());
415
            }
416
417
            echo $template->render(
418
                array(
419
                    'languages' => $this->languages,
420
                    'vocab' => $vocab,
421
                    'term' => $request->getQueryParam('q'),
422
                ));
423
            return;
424
        }
425
        echo $template->render(
426
            array(
427
                'languages' => $this->languages,
428
                'vocab' => $vocab,
429
                'search_results' => $search_results,
430
                'search_count' => $counts,
431
                'rest' => $parameters->getOffset()>0,
432
                'limit_parent' => $parameters->getParentLimit(),
433
                'limit_type' =>  $request->getQueryParam('type') ? explode('+', $request->getQueryParam('type')) : null,
434
                'limit_group' => $parameters->getGroupLimit(),
435
                'limit_scheme' =>  $request->getQueryParam('scheme') ? explode('+', $request->getQueryParam('scheme')) : null,
436
                'group_index' => $vocab->listConceptGroups($request->getContentLang()),
437
                'parameters' => $parameters,
438
                'term' => $request->getQueryParam('q'),
439
                'types' => $vocab_types,
440
                'explicit_langcodes' => $langcodes,
441
                'request' => $request,
442
            ));
443
    }
444
445
    /**
446
     * Invokes the alphabetical listing for a specific vocabulary.
447
     */
448
    public function invokeAlphabeticalIndex($request)
449
    {
450
        $lang = $request->getLang();
451
        $this->setLanguageProperties($lang);
452
        $template = $this->twig->loadTemplate('alphabetical-index.twig');
453
        $vocab = $request->getVocab();
454
455
        $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
456
        if ($request->getQueryParam('limit')) {
457
            $count = $request->getQueryParam('limit');
458
        } else {
459
            $count = ($offset > 0) ? null : 250;
460
        }
461
462
        $content_lang = $request->getContentLang();
463
464
        $all_at_once = $vocab->getConfig()->getAlphabeticalFull();
465
        if (!$all_at_once) {
466
            $search_results = $vocab->searchConceptsAlphabetical($request->getLetter(), $count, $offset, $content_lang);
467
            $letters = $vocab->getAlphabet($content_lang);
468
        } else {
469
            $search_results = $vocab->searchConceptsAlphabetical('*', null, null, $content_lang);
470
            $letters = null;
471
        }
472
473
        $request->setContentLang($content_lang);
474
475
        echo $template->render(
476
            array(
477
                'languages' => $this->languages,
478
                'vocab' => $vocab,
479
                'alpha_results' => $search_results,
480
                'letters' => $letters,
481
                'all_letters' => $all_at_once,
482
                'request' => $request,
483
            ));
484
    }
485
486
    /**
487
     * Invokes the vocabulary group index page template.
488
     * @param boolean $stats set to true to get vocabulary statistics visible.
489
     */
490 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...
491
    {
492
        $lang = $request->getLang();
493
        $this->setLanguageProperties($lang);
494
        $template = $this->twig->loadTemplate('group-index.twig');
495
        $vocab = $request->getVocab();
496
497
        echo $template->render(
498
            array(
499
                'languages' => $this->languages,
500
                'stats' => $stats,
501
                'vocab' => $vocab,
502
                'request' => $request,
503
            ));
504
    }
505
506
    /**
507
     * Loads and renders the view containing a specific vocabulary.
508
     */
509
    public function invokeVocabularyHome($request)
510
    {
511
        $lang = $request->getLang();
512
        // set language parameters for gettext
513
        $this->setLanguageProperties($lang);
514
        $vocab = $request->getVocab();
515
516
        $defaultView = $vocab->getConfig()->getDefaultSidebarView();
517
        // load template
518
        if ($defaultView === 'groups') {
519
            $this->invokeGroupIndex($request, true);
520
            return;
521
        }
522
523
        $template = $this->twig->loadTemplate('vocab.twig');
524
525
        echo $template->render(
526
            array(
527
                'languages' => $this->languages,
528
                'vocab' => $vocab,
529
                'search_letter' => 'A',
530
                'active_tab' => $defaultView,
531
                'request' => $request,
532
            ));
533
    }
534
535
    /**
536
     * Invokes a very generic errorpage.
537
     */
538
    public function invokeGenericErrorPage($request, $message = null)
539
    {
540
        $this->setLanguageProperties($request->getLang());
541
        header("HTTP/1.0 404 Not Found");
542
        $template = $this->twig->loadTemplate('error-page.twig');
543
        echo $template->render(
544
            array(
545
                'languages' => $this->languages,
546
                'request' => $request,
547
                'message' => $message,
548
                'requested_page' => filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_STRING),
549
            ));
550
    }
551
552
    /**
553
     * Loads and renders the view containing a list of recent changes in the vocabulary.
554
     * @param Request $request
555
     */
556
    public function invokeChangeList($request, $prop='dc:created')
557
    {
558
        // set language parameters for gettext
559
        $this->setLanguageProperties($request->getLang());
560
        $vocab = $request->getVocab();
561
        $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
562
        $changeList = $vocab->getChangeList($prop, $request->getContentLang(), $request->getLang(), $offset);
563
        // load template
564
        $template = $this->twig->loadTemplate('changes.twig');
565
566
        // render template
567
        echo $template->render(
568
            array(
569
                'vocab' => $vocab,
570
                'languages' => $this->languages,
571
                'request' => $request,
572
                'changeList' => $changeList)
573
            );
574
    }
575
576
}
577