Skip to content

Commit 588cdaf

Browse files
committed
Support inclusion of configuration
This adds repeatable configuration property `skosmos:includeConfig` to include configuration from file or URL. The configuration is cached as usual, based on modification time of `config.ttl` only. See #1403 for discussion.
1 parent a22b389 commit 588cdaf

File tree

7 files changed

+114
-19
lines changed

7 files changed

+114
-19
lines changed

model/GlobalConfig.php

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ private function initializeConfig()
7878
$nskey = "namespaces of " . $key;
7979
$this->graph = $this->cache->fetch($key);
8080
$this->namespaces = $this->cache->fetch($nskey);
81-
if ($this->graph === false || $this->namespaces === false) { // was not found in cache
81+
if ($this->graph && $this->namespaces) { // found in cache
82+
$this->resource = $this->configResource($this->graph, "cache");
83+
} else {
8284
$this->parseConfig($this->filePath);
8385
$this->cache->store($key, $this->graph);
8486
$this->cache->store($nskey, $this->namespaces);
@@ -88,29 +90,80 @@ private function initializeConfig()
8890
$this->parseConfig($this->filePath);
8991
}
9092

91-
$configResources = $this->graph->allOfType("skosmos:Configuration");
92-
if (is_null($configResources) || !is_array($configResources) || count($configResources) !== 1) {
93-
throw new Exception("config.ttl must have exactly one skosmos:Configuration");
94-
}
95-
96-
$this->resource = $configResources[0];
9793
$this->initializeNamespaces();
9894
} catch (Exception $e) {
9995
echo "Error: " . $e->getMessage();
10096
}
10197
}
10298

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.
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+
103150
/**
104151
* Parses configuration from the config.ttl file
105152
* @param string $filename path to config.ttl file
106153
* @throws \EasyRdf\Exception
107154
*/
108155
private function parseConfig($filename)
109156
{
110-
$this->graph = new EasyRdf\Graph();
111157
$parser = new SkosmosTurtleParser();
112-
$parser->parse($this->graph, file_get_contents($filename), 'turtle', $filename);
158+
$this->graph = $parser->parseGraph(file_get_contents($filename), $filename);
113159
$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+
}
114167
}
115168

116169
/**

model/SkosmosTurtleParser.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,14 @@ public function getNamespaces()
1111
return $this->namespaces;
1212
}
1313

14+
/**
15+
* Parse Turtle into a new Graph and return it.
16+
* @return EasyRdf\Graph
17+
*/
18+
public function parseGraph($data, $baseUri)
19+
{
20+
$graph = new EasyRdf\Graph();
21+
$this->parse($graph, $data, 'turtle', $baseUri);
22+
return $graph;
23+
}
1424
}

tests/GlobalConfigTest.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ public function testGetUiLanguageDropdown()
116116
$this->assertEquals(true, $this->config->getUiLanguageDropdown());
117117
}
118118

119+
public function testGetGlobalPlugins()
120+
{
121+
$this->assertEquals(["alpha", "Bravo", "charlie"], $this->config->getGlobalPlugins());
122+
}
123+
124+
// included from testconfig-included.ttl
125+
119126
public function testGetHoneypotEnabled()
120127
{
121128
$this->assertEquals(false, $this->config->getHoneypotEnabled());
@@ -126,17 +133,21 @@ public function testGetHoneypotTime()
126133
$this->assertEquals(2, $this->config->getHoneypotTime());
127134
}
128135

129-
public function testGetGlobalPlugins()
130-
{
131-
$this->assertEquals(["alpha", "Bravo", "charlie"], $this->config->getGlobalPlugins());
136+
// --- test inclusion from URL
137+
138+
public function testInclusionFromURL() {
139+
$conf = new GlobalConfig("/../tests/testconfig-include.ttl");
140+
$this->assertEquals(2, $conf->getHoneypotTime());
132141
}
133142

134143
// --- tests for the exception paths
135144

136145
public function testInitializeConfigWithoutGraph()
137146
{
138-
$this->expectOutputString('Error: config.ttl must have exactly one skosmos:Configuration');
139-
$conf = new GlobalConfig('/../tests/testconfig-nograph.ttl');
147+
$file = '/../tests/testconfig-nograph.ttl';
148+
$filepath = realpath( dirname(__FILE__) . $file );
149+
$this->expectOutputString("Error: $filepath must have exactly one skosmos:Configuration");
150+
$conf = new GlobalConfig($file);
140151
$this->assertNotNull($conf);
141152
}
142153

tests/init_fuseki.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ for fn in ../test-vocab-data/*.ttl; do
3333
$(./bin/s-put http://localhost:13030/skosmos-test/data "http://www.skosmos.skos/$name/" "$fn")
3434
done
3535

36+
$(./bin/s-put http://localhost:13030/skosmos-test/data "http://skosmos.config/" "../testconfig-included.ttl")
37+
3638
cd ..
3739

tests/testconfig-include.ttl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@prefix skosmos: <http://purl.org/net/skosmos#> .
2+
@prefix : <http://base/#> .
3+
4+
:config a skosmos:Configuration ;
5+
6+
# include configuration from from URL
7+
skosmos:includeConfig <http://localhost:13030/skosmos-test/data?graph=http://skosmos.config/> .
8+

tests/testconfig-included.ttl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@prefix skosmos: <http://purl.org/net/skosmos#> .
2+
3+
# This configuration is being included from file
4+
5+
<http://example.org/> a skosmos:Configuration ;
6+
7+
# whether to enable the spam honey pot or not, enabled by default
8+
skosmos:uiHoneypotEnabled false ;
9+
10+
# default time a user must wait before submitting a form
11+
skosmos:uiHoneypotTime 2 .
12+

tests/testconfig.ttl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,11 @@
5959
skosmos:feedbackEnvelopeSender "skosmos tests" ;
6060
# whether to display the ui language selection as a dropdown (useful for cases where there are more than 3 languages)
6161
skosmos:uiLanguageDropdown true ;
62-
# whether to enable the spam honey pot or not, enabled by default
63-
skosmos:uiHoneypotEnabled false ;
64-
# default time a user must wait before submitting a form
65-
skosmos:uiHoneypotTime 2 ;
6662
# plugins to activate for the whole installation (including all vocabularies)
67-
skosmos:globalPlugins ("alpha" "Bravo" "charlie") .
63+
skosmos:globalPlugins ("alpha" "Bravo" "charlie") ;
64+
65+
# include another config file
66+
skosmos:includeConfig <testconfig-included.ttl> .
6867

6968
# Skosmos vocabularies
7069

0 commit comments

Comments
 (0)