Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support inclusion of configuration #1412

Open
wants to merge 1 commit into
base: skosmos-2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 66 additions & 9 deletions model/GlobalConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ private function initializeConfig()
$nskey = "namespaces of " . $key;
$this->graph = $this->cache->fetch($key);
$this->namespaces = $this->cache->fetch($nskey);
if ($this->graph === false || $this->namespaces === false) { // was not found in cache
if ($this->graph && $this->namespaces) { // found in cache
$this->resource = $this->configResource($this->graph, "cache");
} else {
$this->parseConfig($this->filePath);
$this->cache->store($key, $this->graph);
$this->cache->store($nskey, $this->namespaces);
Expand All @@ -88,29 +90,84 @@ private function initializeConfig()
$this->parseConfig($this->filePath);
}

$configResources = $this->graph->allOfType("skosmos:Configuration");
if (is_null($configResources) || !is_array($configResources) || count($configResources) !== 1) {
throw new Exception("config.ttl must have exactly one skosmos:Configuration");
}

$this->resource = $configResources[0];
$this->initializeNamespaces();
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
}

/**
* Ensure there is exactely one skosmos:Configuration and return it.
*/
private function configResource($graph, $source) {
$configResources = $graph->allOfType("skosmos:Configuration");
if (is_null($configResources) || !is_array($configResources) || count($configResources) !== 1) {
throw new Exception("$source must have exactly one skosmos:Configuration");
}
return $configResources[0];
}

/**
* Retrieves, parses and includes configuration in existing configuration.
* @param \EasyRdf\Resource URL or file of configuration in Turtle syntax.
*/
private function includeConfig($location) {
$location = $location->getUri();

if (str_starts_with($location, "http://") || str_starts_with($location, "https://")) {
$ch = curl_init($location);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: text/turtle'));
$turtle = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode != 200 && $httpCode != 303) {
throw new Exception("Failed to include configuration from $location");
}
curl_close($ch);
} else {
if (file_exists($location)) {
$turtle = file_get_contents($location);
} else {
throw new Exception("Included config file $location does not exist!");
}
}

$parser = new SkosmosTurtleParser();
try {
$graph = $parser->parseGraph($turtle, $location);
} catch (Exception $e) {
throw new Exception("Failed to parse $location: " . $e->getMessage());
}

// Add triples from included configuration, adjust :config resource
$configResource = $this->configResource($graph, $location);
foreach($graph->resources() as $resource) {
$subject = $resource == $configResource ? $this->resource : $resource;
foreach($graph->properties($resource) as $property) {
foreach($resource->all($property) as $value) {
$this->graph->add($subject, $property, $value);
}
}
}
}

/**
* Parses configuration from the config.ttl file
* @param string $filename path to config.ttl file
* @throws \EasyRdf\Exception
*/
private function parseConfig($filename)
{
$this->graph = new EasyRdf\Graph();
$parser = new SkosmosTurtleParser();
$parser->parse($this->graph, file_get_contents($filename), 'turtle', $filename);
$this->graph = $parser->parseGraph(file_get_contents($filename), $filename);
$this->namespaces = $parser->getNamespaces();

$this->resource = $this->configResource($this->graph, $filename);

$includes = $this->graph->allResources($this->resource, "skosmos:includeConfig");
foreach($includes as $location) {
$this->includeConfig($location);
}
}

/**
Expand Down
10 changes: 10 additions & 0 deletions model/SkosmosTurtleParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,14 @@ public function getNamespaces()
return $this->namespaces;
}

/**
* Parse Turtle into a new Graph and return it.
* @return EasyRdf\Graph
*/
public function parseGraph($data, $baseUri)
{
$graph = new EasyRdf\Graph();
$this->parse($graph, $data, 'turtle', $baseUri);
return $graph;
}
}
25 changes: 20 additions & 5 deletions tests/GlobalConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ public function testGetUiLanguageDropdown()
$this->assertEquals(true, $this->config->getUiLanguageDropdown());
}

public function testGetGlobalPlugins()
{
$this->assertEquals(["alpha", "Bravo", "charlie"], $this->config->getGlobalPlugins());
}

// included from testconfig-included.ttl

public function testGetHoneypotEnabled()
{
$this->assertEquals(false, $this->config->getHoneypotEnabled());
Expand All @@ -126,17 +133,25 @@ public function testGetHoneypotTime()
$this->assertEquals(2, $this->config->getHoneypotTime());
}

public function testGetGlobalPlugins()
{
$this->assertEquals(["alpha", "Bravo", "charlie"], $this->config->getGlobalPlugins());
public function testVocabularyExists() {
$this->assertEquals(4, count($this->config->getGraph()->allOfType('skos:Concept')));
}

// --- test inclusion from URL

public function testInclusionFromURL() {
$conf = new GlobalConfig("/../tests/testconfig-include.ttl");
$this->assertEquals(2, $conf->getHoneypotTime());
}

// --- tests for the exception paths

public function testInitializeConfigWithoutGraph()
{
$this->expectOutputString('Error: config.ttl must have exactly one skosmos:Configuration');
$conf = new GlobalConfig('/../tests/testconfig-nograph.ttl');
$file = '/../tests/testconfig-nograph.ttl';
$filepath = realpath( dirname(__FILE__) . $file );
$this->expectOutputString("Error: $filepath must have exactly one skosmos:Configuration");
$conf = new GlobalConfig($file);
$this->assertNotNull($conf);
}

Expand Down
2 changes: 2 additions & 0 deletions tests/init_fuseki.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ for fn in ../test-vocab-data/*.ttl; do
$(./bin/s-put http://localhost:13030/skosmos-test/data "http://www.skosmos.skos/$name/" "$fn")
done

$(./bin/s-put http://localhost:13030/skosmos-test/data "http://skosmos.config/" "../testconfig-included.ttl")

cd ..

8 changes: 8 additions & 0 deletions tests/testconfig-include.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@prefix skosmos: <http://purl.org/net/skosmos#> .
@prefix : <http://base/#> .

:config a skosmos:Configuration ;

# include configuration from from URL
skosmos:includeConfig <http://localhost:13030/skosmos-test/data?graph=http://skosmos.config/> .

14 changes: 14 additions & 0 deletions tests/testconfig-included.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@prefix skosmos: <http://purl.org/net/skosmos#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .

# This configuration is being included from file

<http://example.org/> a skosmos:Configuration ;

# whether to enable the spam honey pot or not, enabled by default
skosmos:uiHoneypotEnabled false ;

# default time a user must wait before submitting a form
skosmos:uiHoneypotTime 2 .

<whatever> a skos:Concept .
9 changes: 4 additions & 5 deletions tests/testconfig.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,11 @@
skosmos:feedbackEnvelopeSender "skosmos tests" ;
# whether to display the ui language selection as a dropdown (useful for cases where there are more than 3 languages)
skosmos:uiLanguageDropdown true ;
# whether to enable the spam honey pot or not, enabled by default
skosmos:uiHoneypotEnabled false ;
# default time a user must wait before submitting a form
skosmos:uiHoneypotTime 2 ;
# plugins to activate for the whole installation (including all vocabularies)
skosmos:globalPlugins ("alpha" "Bravo" "charlie") .
skosmos:globalPlugins ("alpha" "Bravo" "charlie") ;

# include another config file
skosmos:includeConfig <testconfig-included.ttl> .

# Skosmos vocabularies

Expand Down