/** * 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(); } } }
public function testCreateNodeInstanceUri() { $node = NodeUtils::createNodeInstance(new NodeFactoryImpl(), 'http://foo', 'uri'); $this->assertEquals(new NamedNodeImpl('http://foo'), $node); }