Passed
Pull Request — master (#1412)
by Jakob
03:09
created

GlobalConfig::configResource()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 2
nop 2
dl 0
loc 6
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
    public function __construct($config_name='/../config.ttl')
34
    {
35
        $this->cache = new Cache();
36
        try {
37
            $this->filePath = realpath( dirname(__FILE__) . $config_name );
38
            if (!file_exists($this->filePath)) {
39
                throw new Exception('config.ttl file is missing, please provide one.');
40
            }
41
            $this->initializeConfig();
42
        } catch (Exception $e) {
43
            echo "Error: " . $e->getMessage();
44
            return;
45
        }
46
    }
47
48
    public function getCache()
49
    {
50
        return $this->cache;
51
    }
52
53
    /**
54
     * @return int the time the config file was last modified
55
     */
56
    public function getConfigModifiedTime()
57
    {
58
        return $this->configModifiedTime;
59
    }
60
61
    /**
62
     * Initialize configuration, reading the configuration file from the disk,
63
     * and creating the graph and resources objects. Uses a cache if available,
64
     * in order to avoid re-loading the complete configuration on each request.
65
     */
66
    private function initializeConfig()
67
    {
68
        try {
69
            // retrieve last modified time for config file (filemtime returns int|bool!)
70
            $configModifiedTime = filemtime($this->filePath);
71
            if (!is_bool($configModifiedTime)) {
0 ignored issues
show
introduced by
The condition is_bool($configModifiedTime) is always false.
Loading history...
72
                $this->configModifiedTime = $configModifiedTime;
73
            }
74
            // use APC user cache to store parsed config.ttl configuration
75
            if ($this->cache->isAvailable() && !is_null($this->configModifiedTime)) {
76
                // @codeCoverageIgnoreStart
77
                $key = realpath($this->filePath) . ", " . $this->configModifiedTime;
78
                $nskey = "namespaces of " . $key;
79
                $this->graph = $this->cache->fetch($key);
80
                $this->namespaces = $this->cache->fetch($nskey);
81
                if ($this->graph && $this->namespaces) { // found in cache
82
                    $this->resource = $this->configResource($this->graph, "cache");
83
                } else {
84
                    $this->parseConfig($this->filePath);
85
                    $this->cache->store($key, $this->graph);
86
                    $this->cache->store($nskey, $this->namespaces);
87
                }
88
                // @codeCoverageIgnoreEnd
89
            } else { // APC not available, parse on every request
90
                $this->parseConfig($this->filePath);
91
            }
92
93
            $this->initializeNamespaces();
94
        } catch (Exception $e) {
95
            echo "Error: " . $e->getMessage();
96
        }      
97
    }
98
99
    /**
100
     * Ensure there is exactely one skosmos:Configuration and return it.
101
     */
102
    private function configResource($graph, $source) {
103
        $configResources = $graph->allOfType("skosmos:Configuration");
104
        if (is_null($configResources) || !is_array($configResources) || count($configResources) !== 1) {
105
            throw new Exception("$source must have exactly one skosmos:Configuration");
106
        }
107
        return $configResources[0];
108
    }
109
110
    /**
111
     * Retrieves, parses and includes configuration in existing configuration.
112
     * @param \EasyRdf\Resource URL or file of configuration in Turtle syntax.
0 ignored issues
show
Bug introduced by
The type URL 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...
113
     */
114
    private function includeConfig($location) {
115
        $location = $location->getUri();
116
117
        if (str_starts_with($location, "http://") || str_starts_with($location, "https://")) {
118
            $ch = curl_init($location);
119
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
120
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: text/turtle'));
121
            $turtle = curl_exec($ch);
122
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
123
            if ($httpCode != 200 && $httpCode != 303) {
124
                throw new Exception("Failed to include configuration from $location");
125
            }
126
            curl_close($ch);
127
        } else {
128
            if (file_exists($location)) {
129
                $turtle = file_get_contents($location);
130
            } else {
131
                throw new Exception("Included config file $location does not exist!");
132
            }
133
        }
134
135
        $parser = new SkosmosTurtleParser();
136
        try {
137
            $graph = $parser->parseGraph($turtle, $location);
138
        } catch (Exception $e) {
139
            throw new Exception("Failed to parse $location: " . $e->getMessage());
140
        }
141
142
        $configResource = $this->configResource($graph, $location);
143
        foreach($graph->properties($configResource) as $property) {
144
            foreach($configResource->all($property) as $value) {
145
                $this->graph->add($this->resource, $property, $value);
146
            }
147
        }
148
    }
149
150
    /**
151
     * Parses configuration from the config.ttl file
152
     * @param string $filename path to config.ttl file
153
     * @throws \EasyRdf\Exception
154
     */
155
    private function parseConfig($filename)
156
    {
157
        $parser = new SkosmosTurtleParser();
158
        $this->graph = $parser->parseGraph(file_get_contents($filename), $filename);
159
        $this->namespaces = $parser->getNamespaces();
160
161
        $this->resource = $this->configResource($this->graph, $filename);
162
163
        $includes = $this->graph->allResources($this->resource, "skosmos:includeConfig");
164
        foreach($includes as $location) {
165
            $this->includeConfig($location);
166
        }
167
    }
168
169
    /**
170
     * Returns the graph created after parsing the configuration file.
171
     * @return \EasyRdf\Graph
172
     */
173
    public function getGraph()
174
    {
175
        return $this->graph;
176
    }
177
178
    /**
179
     * Registers RDF namespaces from the config.ttl file for use by EasyRdf (e.g. serializing)
180
     */
181
    private function initializeNamespaces() {
182
        foreach ($this->namespaces as $prefix => $fullUri) {
183
            if ($prefix != '' && EasyRdf\RdfNamespace::get($prefix) === null) // if not already defined
184
            {
185
                EasyRdf\RdfNamespace::set($prefix, $fullUri);
186
            }
187
        }
188
    }
189
190
    /**
191
     * Returns the UI languages specified in the configuration or defaults to
192
     * only show English
193
     * @return array
194
     */
195
    public function getLanguages()
196
    {
197
        $languageResources = $this->getResource()->getResource('skosmos:languages');
198
        if (!is_null($languageResources) && !empty($languageResources)) {
199
            $languages = array();
200
            foreach ($languageResources as $languageResource) {
201
                /** @var \EasyRdf\Literal $languageName */
202
                $languageName = $languageResource->getLiteral('rdfs:label');
203
                /** @var \EasyRdf\Literal $languageValue */
204
                $languageValue = $languageResource->getLiteral('rdf:value');
205
                if ($languageName && $languageValue) {
206
                    $languages[$languageName->getValue()] = $languageValue->getValue();
207
                }
208
            }
209
            return $languages;
210
        } else {
211
            return array('en' => 'en_GB.utf8');
212
        }
213
    }
214
215
    /**
216
     * Returns the external HTTP request timeout in seconds or the default value
217
     * of 5 seconds if not specified in the configuration.
218
     * @return integer
219
     */
220
    public function getHttpTimeout()
221
    {
222
        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...
223
    }
224
225
    /**
226
     * Returns the SPARQL HTTP request timeout in seconds or the default value
227
     * of 20 seconds if not specified in the configuration.
228
     * @return integer
229
     */
230
    public function getSparqlTimeout()
231
    {
232
        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...
233
    }
234
235
    /**
236
     * Returns the sparql endpoint address defined in the configuration. If
237
     * not then defaulting to http://localhost:3030/ds/sparql
238
     * @return string
239
     */
240
    public function getDefaultEndpoint()
241
    {
242
        $endpoint = $this->resource->get('skosmos:sparqlEndpoint');
243
        if ($endpoint) {
244
            return $endpoint->getUri();
245
        } elseif (getenv('SKOSMOS_SPARQL_ENDPOINT')) {
246
            return getenv('SKOSMOS_SPARQL_ENDPOINT');
247
        } else {
248
            return 'http://localhost:3030/ds/sparql';
249
        }
250
    }
251
252
    /**
253
     * Returns the maximum number of items to return in transitive queries if defined
254
     * in the configuration or the default value of 1000.
255
     * @return integer
256
     */
257
    public function getDefaultTransitiveLimit()
258
    {
259
        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...
260
    }
261
262
    /**
263
     * Returns the maximum number of items to load at a time if defined
264
     * in the configuration or the default value of 20.
265
     * @return integer
266
     */
267
    public function getSearchResultsSize()
268
    {
269
        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...
270
    }
271
272
    /**
273
     * Returns the configured location for the twig template cache and if not
274
     * defined defaults to "/tmp/skosmos-template-cache"
275
     * @return string
276
     */
277
    public function getTemplateCache()
278
    {
279
        return $this->getLiteral('skosmos:templateCache', '/tmp/skosmos-template-cache');
280
    }
281
282
    /**
283
     * Returns the defined sparql-query extension eg. "JenaText" or
284
     * if not defined falling back to SPARQL 1.1
285
     * @return string
286
     */
287
    public function getDefaultSparqlDialect()
288
    {
289
        return $this->getLiteral('skosmos:sparqlDialect', 'Generic');
290
    }
291
292
    /**
293
     * Returns the feedback address defined in the configuration.
294
     * @return string
295
     */
296
    public function getFeedbackAddress()
297
    {
298
        return $this->getLiteral('skosmos:feedbackAddress', null);
299
    }
300
301
    /**
302
     * Returns the feedback sender address defined in the configuration.
303
     * @return string
304
     */
305
    public function getFeedbackSender()
306
    {
307
        return $this->getLiteral('skosmos:feedbackSender', null);
308
    }
309
310
    /**
311
     * Returns the feedback envelope sender address defined in the configuration.
312
     * @return string
313
     */
314
    public function getFeedbackEnvelopeSender()
315
    {
316
        return $this->getLiteral('skosmos:feedbackEnvelopeSender', null);
317
    }
318
319
    /**
320
     * Returns true if exception logging has been configured.
321
     * @return boolean
322
     */
323
    public function getLogCaughtExceptions()
324
    {
325
        return $this->getBoolean('skosmos:logCaughtExceptions', FALSE);
326
    }
327
328
    /**
329
     * Returns true if browser console logging has been enabled,
330
     * @return boolean
331
     */
332
    public function getLoggingBrowserConsole()
333
    {
334
        return $this->getBoolean('skosmos:logBrowserConsole', FALSE);
335
    }
336
337
    /**
338
     * Returns the name of a log file if configured, or NULL otherwise.
339
     * @return string
340
     */
341
    public function getLoggingFilename()
342
    {
343
        return $this->getLiteral('skosmos:logFileName', null);
344
    }
345
346
    /**
347
     * @return string
348
     */
349
    public function getServiceName()
350
    {
351
        return $this->getLiteral('skosmos:serviceName', 'Skosmos');
352
    }
353
354
    /**
355
     * @return string
356
     */
357
    public function getCustomCss()
358
    {
359
        return $this->getLiteral('skosmos:customCss', null);
360
    }
361
362
    /**
363
     * @return boolean
364
     */
365
    public function getUiLanguageDropdown()
366
    {
367
        return $this->getBoolean('skosmos:uiLanguageDropdown', FALSE);
368
    }
369
370
    /**
371
     * @return string
372
     */
373
    public function getBaseHref()
374
    {
375
        return $this->getLiteral('skosmos:baseHref', null);
376
    }
377
378
    /**
379
     * @return array
380
     */
381
    public function getGlobalPlugins()
382
    {
383
        $globalPlugins = array();
384
        $globalPluginsResource =  $this->getResource()->getResource("skosmos:globalPlugins");
385
        if ($globalPluginsResource) {
0 ignored issues
show
introduced by
$globalPluginsResource is of type EasyRdf\Resource, thus it always evaluated to true.
Loading history...
386
            foreach ($globalPluginsResource as $resource) {
387
                $globalPlugins[] = $resource->getValue();
388
            }
389
        }
390
        return $globalPlugins;
391
    }
392
393
    /**
394
     * @return boolean
395
     */
396
    public function getHoneypotEnabled()
397
    {
398
        return $this->getBoolean('skosmos:uiHoneypotEnabled', TRUE);
399
    }
400
401
    /**
402
     * @return integer
403
     */
404
    public function getHoneypotTime()
405
    {
406
        return $this->getLiteral('skosmos:uiHoneypotTime', 5);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getLiteral...mos:uiHoneypotTime', 5) returns the type string which is incompatible with the documented return type integer.
Loading history...
407
    }
408
409
    /**
410
     * @return boolean
411
     */
412
    public function getCollationEnabled()
413
    {
414
        return $this->getBoolean('skosmos:sparqlCollationEnabled', FALSE);
415
    }
416
}
417