Passed
Pull Request — main (#1866)
by
unknown
03:47
created

GlobalConfig::getFeedbackEnvelopeSender()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Setting some often needed namespace prefixes
5
 */
6
EasyRdf\RdfNamespace::set('skosmos', 'http://purl.org/net/skosmos#');
7
EasyRdf\RdfNamespace::set('skosext', 'http://purl.org/finnonto/schema/skosext#');
8
EasyRdf\RdfNamespace::delete('geo');
9
EasyRdf\RdfNamespace::set('wgs84', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
10
EasyRdf\RdfNamespace::set('isothes', 'http://purl.org/iso25964/skos-thes#');
11
EasyRdf\RdfNamespace::set('mads', 'http://www.loc.gov/mads/rdf/v1#');
12
EasyRdf\RdfNamespace::set('wd', 'http://www.wikidata.org/entity/');
13
EasyRdf\RdfNamespace::set('wdt', 'http://www.wikidata.org/prop/direct/');
14
15
/**
16
 * GlobalConfig provides access to the Skosmos configuration in config.ttl.
17
 */
18
class GlobalConfig extends BaseConfig
19
{
20
    /** Cache reference */
21
    private $cache;
22
    /** Location of the configuration file. Used for caching. */
23
    private $filePath;
24
    /** Namespaces from vocabularies configuration file. */
25
    private $namespaces;
26
    /** EasyRdf\Graph graph */
27
    private $graph;
28
    /**
29
     * @var int the time the config file was last modified
30
     */
31
    private $configModifiedTime = null;
32
33
    private static function getCheckedConfigFileRealPath(string $path): string
34
    {
35
        if (str_starts_with($path, '/')) {
36
            $realpath = realpath($path);
37
        } else {
38
            $realpath = realpath(dirname(__FILE__) . "/" . $path);
39
        }
40
        if (!$realpath) {
41
            throw new Exception('Config file ' . $path . ' is missing, please provide one.');
42
        }
43
        return $realpath;
44
    }
45
46
47
    /**
48
     * Gets the configuration file path.
49
     *
50
     * Returns the full path to the configuration file. If a config name is provided,
51
     * it will be used to construct the path. Otherwise, fallback path will be used.
52
     *
53
     * First fallback is the `SKOSMOS_CONFIG_NAME` environment variable,
54
     * which accepts two formats:
55
     * - Absolute path: A full path to the configuration file (e.g., /etc/skosmos/config.ttl)
56
     * - Relative path: A path relative to the application root (e.g., config/config.ttl)
57
     *
58
     * Second fallback is "config.ttl" path in the root directory.
59
     *
60
     * @param string|null $config_name Optional configuration file name
61
     * @return string The full path to the configuration file. Throws errors on failure,
62
     * e.g. if the file does not exist.
63
     */
64
    private static function getConfigFilePath(?string $config_name = null)
65
    {
66
        if (isset($config_name)) {
67
            return GlobalConfig::getCheckedConfigFileRealPath($config_name);
68
        }
69
        if (!getenv('SKOSMOS_CONFIG_NAME')) {
70
            return GlobalConfig::getCheckedConfigFileRealPath(dirname(__FILE__) . '/../../config.ttl');
71
        }
72
        if (str_starts_with(getenv('SKOSMOS_CONFIG_NAME'), '/')) {
73
            return GlobalConfig::getCheckedConfigFileRealPath(getenv('SKOSMOS_CONFIG_NAME'));
74
        }
75
        return GlobalConfig::getCheckedConfigFileRealPath(dirname(__FILE__) . '/../../' . getenv('SKOSMOS_CONFIG_NAME'));
76
    }
77
78
    public function __construct(Model $model, ?string $config_name = null)
79
    {
80
        $this->cache = new Cache();
81
        $this->filePath = GlobalConfig::getConfigFilePath($config_name);
82
        $resource = $this->initializeConfig();
83
        parent::__construct($model, $resource);
84
    }
85
86
    public function getCache()
87
    {
88
        return $this->cache;
89
    }
90
91
    /**
92
     * @return int the time the config file was last modified
93
     */
94
    public function getConfigModifiedTime()
95
    {
96
        return $this->configModifiedTime;
97
    }
98
99
    /**
100
     * Initialize configuration, reading the configuration file from the disk,
101
     * and creating the graph and resources objects. Uses a cache if available,
102
     * in order to avoid re-loading the complete configuration on each request.
103
     */
104
    private function initializeConfig(): EasyRdf\Resource
105
    {
106
        // retrieve last modified time for config file (filemtime returns int|bool!)
107
        $configModifiedTime = filemtime($this->filePath);
108
        if (!is_bool($configModifiedTime)) {
0 ignored issues
show
introduced by
The condition is_bool($configModifiedTime) is always false.
Loading history...
109
            $this->configModifiedTime = $configModifiedTime;
110
        }
111
        // use APC user cache to store parsed config.ttl configuration
112
        if ($this->cache->isAvailable() && !is_null($this->configModifiedTime)) {
113
            // @codeCoverageIgnoreStart
114
            $key = realpath($this->filePath) . ", " . $this->configModifiedTime;
115
            $nskey = "namespaces of " . $key;
116
            $this->graph = $this->cache->fetch($key);
117
            $this->namespaces = $this->cache->fetch($nskey);
118
            if ($this->graph === false || $this->namespaces === false) { // was not found in cache
119
                $this->parseConfig($this->filePath);
120
                $this->cache->store($key, $this->graph);
121
                $this->cache->store($nskey, $this->namespaces);
122
            }
123
            // @codeCoverageIgnoreEnd
124
        } else { // APC not available, parse on every request
125
            $this->parseConfig($this->filePath);
126
        }
127
        $this->initializeNamespaces();
128
129
        $configResources = $this->graph->allOfType("skosmos:Configuration");
130
        if (is_null($configResources) || !is_array($configResources) || count($configResources) !== 1) {
0 ignored issues
show
introduced by
The condition is_array($configResources) is always true.
Loading history...
131
            throw new Exception("config.ttl must have exactly one skosmos:Configuration");
132
        }
133
        return $configResources[0];
134
    }
135
136
    /**
137
     * Parses configuration from the config.ttl file
138
     * @param string $filename path to config.ttl file
139
     * @throws \EasyRdf\Exception
140
     */
141
    private function parseConfig($filename)
142
    {
143
        $this->graph = new EasyRdf\Graph();
144
        $parser = new SkosmosTurtleParser();
145
        $parser->parse($this->graph, file_get_contents($filename), 'turtle', $filename);
146
        $this->namespaces = $parser->getNamespaces();
147
    }
148
149
    /**
150
     * Returns the graph created after parsing the configuration file.
151
     * @return \EasyRdf\Graph
152
     */
153
    public function getGraph()
154
    {
155
        return $this->graph;
156
    }
157
158
    /**
159
     * Registers RDF namespaces from the config.ttl file for use by EasyRdf (e.g. serializing)
160
     */
161
    private function initializeNamespaces()
162
    {
163
        foreach ($this->namespaces as $prefix => $fullUri) {
164
            if ($prefix != '' && EasyRdf\RdfNamespace::get($prefix) === null) { // if not already defined
165
                EasyRdf\RdfNamespace::set($prefix, $fullUri);
166
            }
167
        }
168
    }
169
170
    /**
171
     * Returns the UI languages specified in the configuration or defaults to
172
     * only show English
173
     * @return array
174
     */
175
    public function getLanguages()
176
    {
177
        $languageResources = $this->getResource()->getResource('skosmos:languages');
178
        if (!is_null($languageResources) && !empty($languageResources)) {
179
            $languages = array();
180
            foreach ($languageResources as $languageResource) {
181
                /** @var \EasyRdf\Literal $languageName */
182
                $languageName = $languageResource->getLiteral('rdfs:label');
183
                /** @var \EasyRdf\Literal $languageValue */
184
                $languageValue = $languageResource->getLiteral('rdf:value');
185
                if ($languageName && $languageValue) {
186
                    $languages[$languageName->getValue()] = $languageValue->getValue();
187
                }
188
            }
189
            return $languages;
190
        } else {
191
            return array('en' => 'en_GB.utf8');
192
        }
193
    }
194
195
    /**
196
     * Returns the external HTTP request timeout in seconds or the default value
197
     * of 5 seconds if not specified in the configuration.
198
     * @return integer
199
     */
200
    public function getHttpTimeout()
201
    {
202
        return $this->getLiteral('skosmos:httpTimeout', 5);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getLiteral...kosmos:httpTimeout', 5) returns the type string which is incompatible with the documented return type integer.
Loading history...
203
    }
204
205
    /**
206
     * Returns the SPARQL HTTP request timeout in seconds or the default value
207
     * of 20 seconds if not specified in the configuration.
208
     * @return integer
209
     */
210
    public function getSparqlTimeout()
211
    {
212
        return $this->getLiteral('skosmos:sparqlTimeout', 20);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getLiteral...mos:sparqlTimeout', 20) returns the type string which is incompatible with the documented return type integer.
Loading history...
213
    }
214
215
    /**
216
     * Returns the sparql endpoint address defined in the configuration. If
217
     * not then defaulting to http://localhost:3030/ds/sparql
218
     * @return string
219
     */
220
    public function getDefaultEndpoint()
221
    {
222
        $endpoint = $this->resource->get('skosmos:sparqlEndpoint');
223
        if ($endpoint) {
224
            return $endpoint->getUri();
225
        } elseif (getenv('SKOSMOS_SPARQL_ENDPOINT')) {
226
            return getenv('SKOSMOS_SPARQL_ENDPOINT');
227
        } else {
228
            return 'http://localhost:3030/ds/sparql';
229
        }
230
    }
231
232
    /**
233
     * Returns the maximum number of items to return in transitive queries if defined
234
     * in the configuration or the default value of 1000.
235
     * @return integer
236
     */
237
    public function getDefaultTransitiveLimit()
238
    {
239
        return $this->getLiteral('skosmos:transitiveLimit', 1000);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getLiteral...transitiveLimit', 1000) returns the type string which is incompatible with the documented return type integer.
Loading history...
240
    }
241
242
    /**
243
     * Returns the maximum number of items to load at a time if defined
244
     * in the configuration or the default value of 20.
245
     * @return integer
246
     */
247
    public function getSearchResultsSize()
248
    {
249
        return $this->getLiteral('skosmos:searchResultsSize', 20);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getLiteral...searchResultsSize', 20) returns the type string which is incompatible with the documented return type integer.
Loading history...
250
    }
251
252
    /**
253
     * Returns the configured location for the twig template cache and if not
254
     * defined defaults to "/tmp/skosmos-template-cache"
255
     * @return string
256
     */
257
    public function getTemplateCache()
258
    {
259
        return $this->getLiteral('skosmos:templateCache', '/tmp/skosmos-template-cache');
260
    }
261
262
    /**
263
     * Returns the defined sparql-query extension eg. "JenaText" or
264
     * if not defined falling back to SPARQL 1.1
265
     * @return string
266
     */
267
    public function getDefaultSparqlDialect()
268
    {
269
        return $this->getLiteral('skosmos:sparqlDialect', 'Generic');
270
    }
271
272
    /**
273
     * Returns the feedback address defined in the configuration.
274
     * @return string
275
     */
276
    public function getFeedbackAddress()
277
    {
278
        return $this->getLiteral('skosmos:feedbackAddress', null);
279
    }
280
281
    /**
282
     * Returns the feedback sender address defined in the configuration.
283
     * @return string
284
     */
285
    public function getFeedbackSender()
286
    {
287
        return $this->getLiteral('skosmos:feedbackSender', null);
288
    }
289
290
    /**
291
     * Returns the feedback envelope sender address defined in the configuration.
292
     * @return string
293
     */
294
    public function getFeedbackEnvelopeSender()
295
    {
296
        return $this->getLiteral('skosmos:feedbackEnvelopeSender', null);
297
    }
298
299
    /**
300
     * Returns true if exception logging has been configured.
301
     * @return boolean
302
     */
303
    public function getLogCaughtExceptions()
304
    {
305
        return $this->getBoolean('skosmos:logCaughtExceptions', false);
306
    }
307
308
    /**
309
     * Returns true if browser console logging has been enabled,
310
     * @return boolean
311
     */
312
    public function getLoggingBrowserConsole()
313
    {
314
        return $this->getBoolean('skosmos:logBrowserConsole', false);
315
    }
316
317
    /**
318
     * Returns the name of a log file if configured, or NULL otherwise.
319
     * @return string
320
     */
321
    public function getLoggingFilename()
322
    {
323
        return $this->getLiteral('skosmos:logFileName', null);
324
    }
325
326
    /**
327
     * @return string
328
     */
329
    public function getServiceName()
330
    {
331
        return $this->getLiteral('skosmos:serviceName', 'Skosmos');
332
    }
333
334
    /**
335
     * Returns the long version of the service name in the requested language.
336
     * @return string the long name of the service
337
     */
338
    public function getServiceNameLong($lang)
339
    {
340
        $val = $this->getLiteral('skosmos:serviceNameLong', false, $lang);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $default of BaseConfig::getLiteral(). ( Ignorable by Annotation )

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

340
        $val = $this->getLiteral('skosmos:serviceNameLong', /** @scrutinizer ignore-type */ false, $lang);
Loading history...
341
342
        if ($val === false) {
0 ignored issues
show
introduced by
The condition $val === false is always false.
Loading history...
343
            // fall back to short service name if not configured
344
            return $this->getServiceName();
345
        }
346
347
        return $val;
348
    }
349
350
    /**
351
     * Returns the service description in the requested language.
352
     * @return string the description of the service
353
     */
354
    public function getServiceDescription($lang)
355
    {
356
        return $this->getLiteral('skosmos:serviceDescription', null, $lang);
357
    }
358
359
    /**
360
     * Returns the feedback page description in the requested language.
361
     * @return string the description of the feedback page
362
     */
363
    public function getFeedbackDescription($lang)
364
    {
365
        return $this->getLiteral('skosmos:feedbackDescription', null, $lang);
366
    }
367
368
    /**
369
     * Returns the about page description in the requested language.
370
     * @return string the description of the about page
371
     */
372
    public function getAboutDescription($lang)
373
    {
374
        return $this->getLiteral('skosmos:aboutDescription', null, $lang);
375
    }
376
377
    /**
378
     * @return string
379
     */
380
    public function getCustomCss()
381
    {
382
        return $this->getLiteral('skosmos:customCss', null);
383
    }
384
385
    /**
386
     * @return boolean
387
     */
388
    public function getUiLanguageDropdown()
389
    {
390
        return $this->getBoolean('skosmos:uiLanguageDropdown', false);
391
    }
392
393
    /**
394
     * @return boolean
395
     */
396
    public function getUiDevMode()
397
    {
398
        return $this->getBoolean('skosmos:uiDevMode', false);
399
    }
400
401
    /**
402
     * @return string
403
     */
404
    public function getBaseHref()
405
    {
406
        $baseHref = $this->getLiteral('skosmos:baseHref', null);
407
        if ($baseHref) {
408
            return $baseHref;
409
        } elseif (getenv('SKOSMOS_BASE_HREF')) {
410
            return getenv('SKOSMOS_BASE_HREF');
411
        }
412
    }
413
414
    /**
415
     * @return array
416
     */
417
    public function getGlobalPlugins()
418
    {
419
        $globalPlugins = array();
420
        $globalPluginsResource =  $this->getResource()->getResource("skosmos:globalPlugins");
421
        if ($globalPluginsResource) {
0 ignored issues
show
introduced by
$globalPluginsResource is of type EasyRdf\Resource, thus it always evaluated to true.
Loading history...
422
            foreach ($globalPluginsResource as $resource) {
423
                $globalPlugins[] = $resource->getValue();
424
            }
425
        }
426
        return $globalPlugins;
427
    }
428
429
    /**
430
     * @return boolean
431
     */
432
    public function getHoneypotEnabled()
433
    {
434
        return $this->getBoolean('skosmos:feedbackHoneypotEnabled', true);
435
    }
436
437
    /**
438
     * @return integer
439
     */
440
    public function getHoneypotTime()
441
    {
442
        return $this->getLiteral('skosmos:feedbackHoneypotTime', 5);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getLiteral...edbackHoneypotTime', 5) returns the type string which is incompatible with the documented return type integer.
Loading history...
443
    }
444
445
    /**
446
     * @return boolean
447
     */
448
    public function getCollationEnabled()
449
    {
450
        return $this->getBoolean('skosmos:sparqlCollationEnabled', false);
451
    }
452
}
453