1313EasyRdf \RdfNamespace::set ('wdt ' , 'http://www.wikidata.org/prop/direct/ ' );
1414
1515/**
16- * GlobalConfig provides access to the Skosmos configuration in config.ttl .
16+ * GlobalConfig provides access to the Skosmos configuration.
1717 */
1818class GlobalConfig extends BaseConfig {
1919
@@ -59,7 +59,7 @@ public function getConfigModifiedTime()
5959 }
6060
6161 /**
62- * Initialize configuration, reading the configuration file from the disk,
62+ * Initialize configuration, reading the configuration file from disk or URL ,
6363 * and creating the graph and resources objects. Uses a cache if available,
6464 * in order to avoid re-loading the complete configuration on each request.
6565 */
@@ -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,31 +90,89 @@ 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
10399 /**
104- * Parses configuration from the config.ttl file
105- * @param string $filename path to config.ttl file
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 and parses configuration with optional inclusion.
112+ * @param string file or URL of configuration in Turtle syntax.
113+ * @param int inclusion depth (0 for root configuration)
106114 * @throws \EasyRdf\Exception
107115 */
108- private function parseConfig ($ filename )
109- {
110- $ this ->graph = new EasyRdf \Graph ();
116+ private function parseConfig ($ location , $ depth =0 ) {
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 ("Config file $ location does not exist! " );
132+ }
133+ }
134+
111135 $ parser = new SkosmosTurtleParser ();
112- $ parser ->parse ($ this ->graph , file_get_contents ($ filename ), 'turtle ' , $ filename );
113- $ this ->namespaces = $ parser ->getNamespaces ();
114- }
136+ try {
137+ $ graph = $ parser ->parseGraph ($ turtle , $ location );
138+ $ namespaces = $ parser ->getNamespaces ();
139+ } catch (Exception $ e ) {
140+ throw new Exception ("Failed to parse $ location: " . $ e ->getMessage ());
141+ }
142+
143+ $ configResource = $ this ->configResource ($ graph , $ location );
144+
145+ if ($ depth === 0 ) {
146+ $ this ->graph = $ graph ;
147+ $ this ->namespaces = $ namespaces ;
148+ $ this ->resource = $ configResource ;
149+ } else {
150+ // Add triples to existing configuration
151+ foreach ($ graph ->resources () as $ resource ) {
152+ $ subject = $ resource == $ configResource ? $ this ->resource : $ resource ;
153+ foreach ($ graph ->properties ($ resource ) as $ property ) {
154+ foreach ($ resource ->all ($ property ) as $ value ) {
155+ $ this ->graph ->add ($ subject , $ property , $ value );
156+ }
157+ }
158+ }
159+ // Add namespaces unless prefix has been defined
160+ foreach ($ namespaces as $ prefix => $ fullUri ) {
161+ if (!isset ($ this ->namespaces [$ prefix ])) {
162+ $ this ->namespaces [$ prefix ] = $ fullUri ;
163+ }
164+ }
165+ }
115166
167+ // only include up to four levels
168+ if ($ depth < 4 ) {
169+ $ includes = $ this ->graph ->allResources ($ this ->resource , "skosmos:includeConfig " );
170+ foreach ($ includes as $ location ) {
171+ $ this ->parseConfig ($ location ->getUri (), $ depth +1 );
172+ }
173+ }
174+ }
175+
116176 /**
117177 * Returns the graph created after parsing the configuration file.
118178 * @return \EasyRdf\Graph
0 commit comments