/** * Determines type of a entity. * * @param string $entity Entity string. * @return string|null Returns either literal, typed-literal, uri or var. Returns null if it couldnt be * determined. */ public function determineEntityType($entity) { // remove braces at the beginning (only if $entity looks like <http://...>) if ('<' == substr($entity, 0, 1)) { $entity = str_replace(array('>', '<'), '', $entity); } // checks if $entity is an URL if (true === NodeUtils::simpleCheckURI($entity)) { return 'uri'; // checks if ^^< is in $entity OR if $entity is surrounded by quotation marks } elseif (false !== strpos($entity, '"^^<') || '"' == substr($entity, 0, 1) && '"' == substr($entity, strlen($entity) - 1, 1)) { return 'typed-literal'; // checks if $entity is an URL, which was written with prefix, such as rdfs:label } elseif (false !== strpos($entity, ':')) { return 'uri'; // checks if "@ is in $entity } elseif (false !== strpos($entity, '"@')) { return 'literal'; // checks if $entity is a string; only strings can be a variable } elseif (true === is_string($entity)) { return 'var'; // unknown type } else { return null; } }
public function testSimpleCheckURI() { $this->assertFalse(NodeUtils::simpleCheckURI('')); $this->assertFalse(NodeUtils::simpleCheckURI('http//foobar/')); $this->assertTrue(NodeUtils::simpleCheckURI('http:foobar/')); $this->assertTrue(NodeUtils::simpleCheckURI('http://foobar/')); $this->assertTrue(NodeUtils::simpleCheckURI('http://*****:*****@foobar/')); }
/** * @param string $uri URI of the new named node. * @return NamedNode */ public function createNamedNode($uri) { if ($uri === null) { throw new \Exception('Can\'t initialize node with null.'); } if (!NodeUtils::simpleCheckURI($uri)) { throw new \Exception('Invalid URI was given for RDF NamedNode creation.'); } // TODO catch invalid URIs $world = librdf_php_get_world(); $uri = librdf_new_uri($world, $uri); $redlandNode = librdf_new_node_from_uri($world, $uri); if ($redlandNode === null) { throw new \Exception('Initialization of redland node failed.'); } return new NamedNode($redlandNode); }
/** * This method sends a SPARQL query to the store. * * @param string $query The SPARQL query to send to the store. * @param array $options optional It contains key-value pairs and should provide additional * introductions for the store and/or its adapter(s). * @return Result Returns result of the query. Its type depends on the type of the query. * @throws \Exception If query is no string. * @throws \Exception If query is malformed. * @throws \Exception If query is a DELETE query and contains quads, where the graph of one quad is of type var * @throws \Exception If a non-graph query contains no triples and quads. * @todo handle multiple graphs in FROM clause */ public function query($query, array $options = array()) { $queryObject = $this->queryFactory->createInstanceByQueryString($query); $queryParts = $queryObject->getQueryParts(); // if a non-graph query was given, we assume triples or quads. If neither quads nor triples were found, // throw an exception. if (false === $queryObject->isGraphQuery() && false === isset($queryParts['triple_pattern']) && false === isset($queryParts['quad_pattern'])) { throw new \Exception('Non-graph queries must have triples or quads.'); } // execute query on the store $result = $this->store->query($query); /* * special case: if you execute a SELECT COUNT(*) query, ARC2 will return the number of triples instead of a result set */ $countCheck = preg_match('/selectcount\\([a-z*]\\)(from|where)/si', preg_replace('/\\s+/', '', $query)); if (1 == $countCheck) { $variable = 'callret-0'; // build a set result, because the user expects it as result type because a SELECT query // was sent. $setResult = $this->resultFactory->createSetResult(array(array($variable => $this->nodeFactory->createLiteral($result, 'http://www.w3.org/2001/XMLSchema#int')))); $setResult->setVariables(array($variable)); return $setResult; /* * ARC2 does not support quads, especially not in DELETE queries. The following code construct * tries to close that gap by transforming the query in a one which ARC2 can understand. * * This part transform queries of the kind: * * DELETE WHERE { * Graph <http://localhost/Saft/TestGraph/> { * ?s ?p ?o . * } * } * * to SPARQL+ ones: * * DELETE FROM <http://localhost/Saft/TestGraph/> { * ?s ?p ?o . * } * WHERE { * ?s ?p ?o . * } * * * IMPORTANT: Please adapt * https://github.com/SaftIng/safting.github.io/blob/master/doc/phpframework/addition/ARC2.md * if you change the support for SPARQL 1.0/1.1 here! */ } elseif ($queryObject->isUpdateQuery() && isset($queryParts['quad_pattern']) && 'deleteWhere' === $queryParts['sub_type']) { foreach ($queryParts['quad_pattern'] as $quad) { if ('uri' != $quad['g_type']) { throw new \Exception('The graph of a quad must be an URI here.'); } // subject $s = NodeUtils::createNodeInstance($this->nodeFactory, $quad['s'], $quad['s_type']); $s = SparqlUtils::getNodeInSparqlFormat($s); // predicate $p = NodeUtils::createNodeInstance($this->nodeFactory, $quad['p'], $quad['p_type']); $p = SparqlUtils::getNodeInSparqlFormat($p); // object $o = NodeUtils::createNodeInstance($this->nodeFactory, $quad['o'], $quad['o_type'], $quad['o_datatype'], $quad['o_lang']); $o = SparqlUtils::getNodeInSparqlFormat($o); return $this->query('DELETE FROM <' . $quad['g'] . '> {' . $s . ' ' . $p . ' ' . $o . ' } WHERE {' . $s . ' ' . $p . ' ' . $o . ' }'); } /* * SELECT query */ } elseif ('selectQuery' === AbstractQuery::getQueryType($query)) { /* * For a SELECT query the result looks like: * * array( * 'query_time' => 0.2 * 'query_type' => 'select', * 'result' => array( * 'variables' => array('s', 'o') * 'rows' => * array( * 's' => "http://s/" * 's type' => 'uri', * 'o' => '42', * 'o type' => "literal" * 'o datatype' => "http://www.w3.org/2001/XMLSchema#string" * ) */ $entries = array(); // go through all rows foreach ($result['result']['rows'] as $row) { $newEntry = array(); foreach ($result['result']['variables'] as $variable) { // checks for variable type // example: $row['s type'] switch ($row[$variable . ' type']) { // ARC2 does not differenciate between typed literal and literal, like Virtuoso does // for instance. You have to check for lang and datatype key by yourself. case 'literal': // if language is set if (isset($row[$variable . ' lang'])) { $newEntry[$variable] = $this->nodeFactory->createLiteral($row[$variable], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', $row[$variable . ' lang']); // if datatype is set } elseif (isset($row[$variable . ' datatype'])) { $newEntry[$variable] = $this->nodeFactory->createLiteral($row[$variable], $row[$variable . ' datatype']); // if neither one is set, we assume its a string and use xsd:string as datatype } else { $newEntry[$variable] = $this->nodeFactory->createLiteral($row[$variable], 'http://www.w3.org/2001/XMLSchema#string'); } break; case 'uri': $newEntry[$variable] = $this->nodeFactory->createNamedNode($row[$variable]); break; } } $entries[] = $newEntry; } // Create and fill SetResult instance $setResult = $this->resultFactory->createSetResult($entries); $setResult->setVariables($result['result']['variables']); return $setResult; } else { if ('askQuery' === AbstractQuery::getQueryType($query)) { return $this->resultFactory->createValueResult($result['result']); } else { return $this->resultFactory->createEmptyResult(); } } }
/** * Transforms a statement array given by EasyRdf to a Saft StatementIterator instance. * * @param array $rdfPhp * @return StatementIterator */ protected function rdfPhpToStatementIterator(array $rdfPhp) { $statements = array(); // go through all subjects foreach ($rdfPhp as $subject => $predicates) { // predicates associated with the subject foreach ($predicates as $property => $objects) { // object(s) foreach ($objects as $object) { /** * Create subject node */ if (true === NodeUtils::simpleCheckURI($subject)) { $s = $this->nodeFactory->createNamedNode($subject); } else { $s = $this->nodeFactory->createLiteral($subject); } /** * Create predicate node */ if (true === NodeUtils::simpleCheckURI($property)) { $p = $this->nodeFactory->createNamedNode($property); } else { $p = $this->nodeFactory->createLiteral($property); } /* * Create object node */ // URI if (NodeUtils::simpleCheckURI($object['value'])) { $o = $this->nodeFactory->createNamedNode($object['value']); // datatype set } elseif (isset($object['datatype'])) { $o = $this->nodeFactory->createLiteral($object['value'], $object['datatype']); // lang set } elseif (isset($object['lang'])) { $o = $this->nodeFactory->createLiteral($object['value'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', $object['lang']); } else { $o = $this->nodeFactory->createLiteral($object['value']); } // build and add statement $statements[] = $this->statementFactory->createStatement($s, $p, $o); } } } return new ArrayStatementIteratorImpl($statements); }
/** * Establish a connection to the endpoint and authenticate. * * @return Client Setup HTTP client. */ protected function openConnection() { $this->client = new Client(); $configuration = array_merge(array('authUrl' => '', 'password' => '', 'queryUrl' => '', 'username' => ''), $this->configuration); // authenticate only if an authUrl was given. if (NodeUtils::simpleCheckURI($configuration['authUrl'])) { $this->authenticateOnServer($configuration['authUrl'], $configuration['username'], $configuration['password']); } // check query URL if (false === NodeUtils::simpleCheckUri($configuration['queryUrl'])) { throw new \Exception('Parameter queryUrl is not an URI or empty: ' . $configuration['queryUrl']); } $this->client->setUrl($configuration['queryUrl']); }
/** * */ public function install() { // read configuration file $this->configuration = json_decode(file_get_contents($this->configurationFilepath), true); if (null == $this->configuration) { throw new \Exception('Configuration file contains invalid JSON.'); } if (0 < count($this->configuration['version'])) { $requirements = array(); foreach ($this->configuration['version'] as $version => $versionEntry) { $requirements = array_merge($requirements, $this->getRequirements($versionEntry['require'])); } // set folder to install requirements if (isset($this->configuration['knowledge-directory'])) { $folderForRequirements = $this->defaultRootFolder . $this->configuration['knowledge-directory'] . '/'; } else { $folderForRequirements = $this->defaultRootFolder . 'knowledge/'; } // if there are requirements to install, create knowledge directory first if (0 < count($requirements) && false == file_exists($folderForRequirements)) { $fileObject = new File($folderForRequirements); $fileObject->mkdirs(); } $nodeUtils = new NodeUtils(); $curl = new Curl(); $curl->setOpt(CURLOPT_ENCODING, 'gzip'); $curl->setOpt(CURLOPT_FOLLOWLOCATION, true); foreach ($requirements as $name => $requirement) { // if a valid local file was given if (file_exists($requirement['file'])) { $fileObject = new File($requirement['file']); $fileObject->copy($targetPath); // if a valid URL was given } elseif ($nodeUtils->simpleCheckURI($requirement['file'])) { // split name to be able to create all folders $name = explode('/', $name); $vendor = $name[0]; $project = $name[1]; // remove all maybe existing files if (file_exists($folderForRequirements . $vendor . '/' . $project . '.ttl')) { $fileObject = new File($folderForRequirements . $vendor . '/' . $project . '.ttl'); $fileObject->delete(); } if (false == file_exists($folderForRequirements . $vendor)) { $fileObject = new File($folderForRequirements . $vendor); $fileObject->mkdirs(); } echo PHP_EOL . '- Download ' . $vendor . '/' . $project; if (isset($requirement['file-format'])) { $fileFormat = $requirement['file-format']; } else { $fileFormat = $this->getFileFormat($requirement['file']); } if (null !== $fileFormat) { $curl->download($requirement['file'], $folderForRequirements . $vendor . '/' . $project . '.' . $fileFormat); if ('xml' == $fileFormat) { $fileFormatForParsing = 'rdf-xml'; } elseif ('ttl' == $fileFormat) { $fileFormatForParsing = 'turtle'; } elseif ('n3' == $fileFormat || 'nt' == $fileFormat) { $fileFormatForParsing = 'n-triples'; } else { $fileFormatForParsing = $fileFormat; } if (isset($this->configuration['target-file-serialization']) && $this->configuration['target-file-serialization'] != $fileFormatForParsing) { // get parser suiteable for the given file format $parserFactory = new ParserFactory(new NodeFactoryImpl(), new StatementFactoryImpl()); $parser = $parserFactory->createParserFor($fileFormatForParsing); if (null == $parser) { echo ' - Unknown file format given: ' . $fileFormatForParsing . '; Leaving file at : ' . $fileFormat; continue; } // parse file content and transform it into a statement $statementIterator = $parser->parseStreamToIterator($folderForRequirements . $vendor . '/' . $project . '.' . $fileFormat); /* go through iterator and output the first few statements $i = 0; foreach ($statementIterator as $statement) { echo (string)$statement->getSubject() . ' ' . (string)$statement->getPredicate() . ' ' . (string)$statement->getObject() . PHP_EOL; if ($i++ == 10) { break; } } continue;*/ // get serializer for target file format $serializerFactory = new SerializerFactory(new NodeFactoryImpl(), new StatementFactoryImpl()); $targetFormatForSerialization = $this->configuration['target-file-serialization']; if ('rdf-xml' == $targetFormatForSerialization) { $serializedFileFormat = 'xml'; } elseif ('turtle' == $targetFormatForSerialization) { $serializedFileFormat = 'ttl'; } elseif ('n-triples' == $targetFormatForSerialization) { $serializedFileFormat = 'n3'; } else { $serializedFileFormat = $targetFormatForSerialization; } $targetFile = 'file://' . $folderForRequirements . $vendor . '/' . $project . '.' . $serializedFileFormat; $serializer = $serializerFactory->createSerializerFor($targetFormatForSerialization); $serializer->serializeIteratorToStream($statementIterator, fopen($targetFile, 'w')); if (file_exists($targetFile)) { unlink($folderForRequirements . $vendor . '/' . $project . '.' . $fileFormat); } } echo ' - done'; } else { echo ' - unknown file format for the ontology reference: ' . $requirement['file']; } } } echo PHP_EOL; } else { return 'No version information found. Did you added elements to version array?'; } }