/** * check and manipulate the declared FROMs according to the access control */ protected function _prepareQuery($queryObject, &$options = array()) { /* * clone the Query2 Object to not modify the original one * could be used elsewhere, could have side-effects */ if ($queryObject instanceof Erfurt_Sparql_Query2) { //always clone //the query will be altered here to implement AC and owl:imports //dont make these changes global $queryObject = clone $queryObject; //bring triples etc. to canonical order // $queryObject->optimize(); } $defaultOptions = array(Erfurt_Store::RESULTFORMAT => Erfurt_Store::RESULTFORMAT_PLAIN, Erfurt_Store::USE_AC => true, Erfurt_Store::USE_OWL_IMPORTS => true, Erfurt_Store::USE_ADDITIONAL_IMPORTS => true); if (!is_array($options)) { $options = array(); } $options = array_merge($defaultOptions, $options); //typechecking if (is_string($queryObject)) { $queryObject = Erfurt_Sparql_SimpleQuery::initWithString($queryObject); } if (!($queryObject instanceof Erfurt_Sparql_Query2 || $queryObject instanceof Erfurt_Sparql_SimpleQuery)) { throw new Erfurt_Store_Exception('Argument 1 passed to Erfurt_Store::sparqlQuery must be instance of ' . 'Erfurt_Sparql_Query2, Erfurt_Sparql_SimpleQuery or string', 1); } /* if ($options[Erfurt_Store::USE_AC] == false) { //we are done preparing early return $queryObject; } */ $logger = $this->_getQueryLogger(); $noBindings = false; //get available models (readable) $available = array(); if ($options[Erfurt_Store::USE_AC] === true) { $logger->debug('AC: use ac '); $availablepre = $this->getAvailableModels(true); //all readable (with ac) foreach ($availablepre as $key => $true) { $available[] = array('uri' => $key, 'named' => false); } } else { $logger->debug('AC: dont use ac '); $allpre = $this->_backendAdapter->getAvailableModels(); //really all (without ac) foreach ($allpre as $key => $true) { $available[] = array('uri' => $key, 'named' => false); } } $logger->debug('AC: available models ' . $this->toStr($available)); // examine froms (for access control and imports) in 5 steps // 1. extract froms for easier handling $froms = array(); if ($queryObject instanceof Erfurt_Sparql_Query2) { foreach ($queryObject->getFroms() as $graphClause) { $uri = $graphClause->getGraphIri()->getIri(); $froms[] = array('uri' => $uri, 'named' => $graphClause->isNamed()); } } else { //SimpleQuery foreach ($queryObject->getFrom() as $graphClause) { $froms[] = array('uri' => $graphClause, 'named' => false); } foreach ($queryObject->getFromNamed() as $graphClause) { $froms[] = array('uri' => $graphClause, 'named' => true); } } $logger->debug('AC: requested FROMs' . $this->toStr($froms)); // 2. no froms in query -> froms = availableModels if (empty($froms)) { $logger->debug('AC: no requested FROM -> take all available: ' . $this->toStr($available)); $froms = $available; } // 3. filter froms by availability and existence - if filtering deletes all -> give empty result back if ($options[Erfurt_Store::USE_AC] === true) { $froms = $this->_maskModelList($froms, $available); $logger->debug('AC: after filtering (read-rights and existence): ' . $this->toStr($froms)); if (empty($froms)) { $logger->debug('AC: all disallowed - empty result'); $noBindings = true; } } // 4. get import closure for every remaining from if ($options[Erfurt_Store::USE_OWL_IMPORTS] === true) { foreach ($froms as $from) { $importsClosure = $this->getImportsClosure($from['uri'], $options[Erfurt_Store::USE_ADDITIONAL_IMPORTS], $options[Erfurt_Store::USE_AC]); $logger->debug('AC: import ' . $from['uri'] . ' -> ' . (empty($importsClosure) ? 'none' : implode(' ', $importsClosure))); foreach ($importsClosure as $importedGraphUri) { $addCandidate = array('uri' => $importedGraphUri, 'named' => false); //avoid duplicates if (in_array($addCandidate, $available) && array_search($addCandidate, $froms) === false) { $froms[] = $addCandidate; } } } } $logger->debug('AC: after imports: ' . $this->toStr($froms)); // 5. put froms back if ($queryObject instanceof Erfurt_Sparql_Query2) { $queryObject->setFroms(array()); foreach ($froms as $from) { $queryObject->addFrom($from['uri'], $from['named']); } } else { $queryObject->setFrom(array()); $queryObject->setFromNamed(array()); foreach ($froms as $from) { if (!$from['named']) { $queryObject->addFrom($from['uri']); } else { $queryObject->addFromNamed($from['uri']); } } } // if there were froms and all got deleted due to access controll - give back empty result set // this is achieved by replacing the where-part with an unsatisfiable one // i think this is efficient because otherwise we would have to deal with result formating und variables if ($noBindings) { $logger->debug('AC: force no bindings'); if ($queryObject instanceof Erfurt_Sparql_SimpleQuery) { $queryObject->setWherePart('{FILTER(false)}'); } else { if ($queryObject instanceof Erfurt_Sparql_Query2) { $ggp = new Erfurt_Sparql_Query2_GroupGraphPattern(); $ggp->addFilter(false); //unsatisfiable $queryObject->removeAllProjectionVars(); $queryObject->setWhere($ggp); } } } return (string) $queryObject; }
/** * Moves resource to new URI * renaming all occurences of the resource. * * @param string $oldUri The URI that identifies the resource. * @param string $newUri The URI to move resource to. * * @return void */ public function renameResource($oldUri, $newUri) { $query = new Erfurt_Sparql_Query2(); $query->setDistinct(true); $vars = array(); foreach (array('s', 'p', 'o') as $varName) { $vars[$varName] = new Erfurt_Sparql_Query2_Var($varName); $query->addProjectionVar($vars[$varName]); } $oldUriRef = new Erfurt_Sparql_Query2_IriRef($oldUri); $union = new Erfurt_Sparql_Query2_GroupOrUnionGraphPattern(); foreach ($vars as $var) { $group = new Erfurt_Sparql_Query2_GroupGraphPattern(); $group->addTriple($vars['s'], $vars['p'], $vars['o']); $group->addFilter(new Erfurt_Sparql_Query2_sameTerm($var, $oldUriRef)); $union->addElement($group); } $query->addElement($union); $result = $this->sparqlQuery($query, array('result_format' => 'extended')); $removed = array(); $added = array(); foreach ($result['results']['bindings'] as $s) { // result format from sparqlQuery // isn't the same as format for delete/addMultipleStatements if (array_key_exists('xml:lang', $s['o'])) { $s['o']['lang'] = $s['o']['xml:lang']; unset($s['o']['xml:lang']); } $removed[$s['s']['value']][$s['p']['value']][] = $s['o']; foreach (array('s', 'p', 'o') as $varName) { if ($s[$varName]['type'] === 'uri' && $s[$varName]['value'] === $oldUri) { $s[$varName]['value'] = $newUri; } } $added[$s['s']['value']][$s['p']['value']][] = $s['o']; } $this->deleteMultipleStatements($removed); $this->addMultipleStatements($added); }