PageRenderTime 65ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/s3db3.5.10/pearlib/rdfapi-php/api/model/DbModel.php

https://code.google.com/p/s3db/
PHP | 1304 lines | 535 code | 236 blank | 533 comment | 116 complexity | 81968525c9817fe76adc4b036f723543 MD5 | raw file
  1. <?php
  2. require_once RDFAPI_INCLUDE_DIR . 'model/Model.php';
  3. require_once RDFAPI_INCLUDE_DIR . 'model/Blanknode.php';
  4. require_once RDFAPI_INCLUDE_DIR . 'model/Statement.php';
  5. // ----------------------------------------------------------------------------------
  6. // Class: DbModel
  7. // ----------------------------------------------------------------------------------
  8. /**
  9. * This class provides methods for manipulating DbModels from DbStore.
  10. * A DbModel is an RDF Model, which is persistently stored in a relational database.
  11. * This Class uses the ADOdb Database Abstraction Library for PHP (http://adodb.sourceforge.net/).
  12. *
  13. *
  14. * @version $Id: DbModel.php,v 1.30 2007/05/29 16:51:52 cweiske Exp $
  15. * @author Radoslaw Oldakowski <radol@gmx.de>
  16. *
  17. * @package model
  18. * @access public
  19. */
  20. class DbModel extends Model{
  21. /**
  22. * Database connection object.
  23. *
  24. * @var object ADOConnection
  25. * @access private
  26. */
  27. var $dbConn;
  28. /**
  29. * Unique model URI.
  30. * Used to identify the DbModel.
  31. *
  32. * @var string
  33. * @access private
  34. */
  35. var $modelURI;
  36. /**
  37. * Database internal modelID.
  38. * Used to avoid JOINs.
  39. *
  40. * @var string
  41. * @access private
  42. */
  43. var $modelID;
  44. /**
  45. * Constructor
  46. * Do not call this directly.
  47. * Use the method getModel,getNewModel or putModel of the Class DbStore instead.
  48. *
  49. * @param object ADOConnection &$dbConnection
  50. * @param string $modelURI
  51. * @param string $modelID
  52. * @param string $baseURI
  53. * @access public
  54. */
  55. function DbModel(&$dbConnection, $modelURI, $modelID, $baseURI=NULL) {
  56. $this->dbConn =& $dbConnection;
  57. $this->modelURI = $modelURI;
  58. $this->modelID = $modelID;
  59. $this->baseURI = $this->_checkBaseURI($baseURI);
  60. }
  61. /**
  62. * Set a base URI for the DbModel.
  63. * Affects creating of new resources and serialization syntax.
  64. *
  65. * @param string $uri
  66. * @throws SqlError
  67. * @access public
  68. */
  69. function setBaseURI($uri) {
  70. $this->baseURI = $this->_checkBaseURI($uri);
  71. $rs = $this->dbConn->execute("UPDATE models SET baseURI='" .$this->baseURI ."'
  72. WHERE modelID=" .$this->modelID);
  73. if (!$rs)
  74. $this->dbConn->errorMsg();
  75. }
  76. /**
  77. * Return the number of statements in this DbModel.
  78. *
  79. * @return integer
  80. * @access public
  81. */
  82. function size() {
  83. $count =& $this->dbConn->getOne('SELECT COUNT(modelID) FROM statements
  84. WHERE modelID = ' .$this->modelID);
  85. return $count;
  86. }
  87. /**
  88. * Check if this DbModel is empty.
  89. *
  90. * @return boolean
  91. * @access public
  92. */
  93. function isEmpty() {
  94. if ($this->size() == 0)
  95. return TRUE;
  96. return FALSE;
  97. }
  98. /**
  99. * Add a new triple to this DbModel.
  100. *
  101. * @param object Statement &$statement
  102. * @throws PhpError
  103. * @throws SqlError
  104. * @access public
  105. * @return mixed true on success, false if the statement is already in the model,
  106. * error message (string) on failure
  107. */
  108. function add(&$statement) {
  109. if (!is_a($statement, 'Statement')) {
  110. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: add): Statement expected.';
  111. trigger_error($errmsg, E_USER_ERROR);
  112. }
  113. if (!$this->contains($statement)) {
  114. $subject_is = $this->_getNodeFlag($statement->subject());
  115. $sql = "INSERT INTO statements
  116. (modelID, subject, predicate, object, l_language, l_datatype, subject_is, object_is)
  117. VALUES
  118. (" .$this->modelID .","
  119. ."'" .$statement->getLabelSubject() ."',"
  120. ."'" .$statement->getLabelPredicate() ."',";
  121. if (is_a($statement->object(), 'Literal')) {
  122. $quotedLiteral = $this->dbConn->qstr($statement->obj->getLabel());
  123. $sql .= $quotedLiteral .","
  124. ."'" .$statement->obj->getLanguage() ."',"
  125. ."'" .$statement->obj->getDatatype() ."',"
  126. ."'" .$subject_is ."',"
  127. ."'l')";
  128. }else{
  129. $object_is = $this->_getNodeFlag($statement->object());
  130. $sql .= "'" .$statement->obj->getLabel() ."',"
  131. ."'',"
  132. ."'',"
  133. ."'" .$subject_is ."',"
  134. ."'" .$object_is ."')";
  135. }
  136. $rs =& $this->dbConn->execute($sql);
  137. if (!$rs) {
  138. return $this->dbConn->errorMsg();
  139. } else {
  140. return true;
  141. }
  142. } else {
  143. return false;
  144. }
  145. }
  146. /**
  147. * Alias for the method add().
  148. *
  149. * @param object Statement &$statement
  150. * @throws PhpError
  151. * @throws SqlError
  152. * @access public
  153. */
  154. function addWithoutDuplicates(&$statement) {
  155. $this->add($statement);
  156. }
  157. /**
  158. * Remove the given triple from this DbModel.
  159. *
  160. * @param object Statement &$statement
  161. * @throws PhpError
  162. * @throws SqlError
  163. * @access public
  164. */
  165. function remove(&$statement) {
  166. if (!is_a($statement, 'Statement')) {
  167. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: remove): Statement expected.';
  168. trigger_error($errmsg, E_USER_ERROR);
  169. }
  170. $sql = 'DELETE FROM statements
  171. WHERE modelID=' .$this->modelID;
  172. $sql .= $this->_createDynSqlPart_SPO ($statement->subj, $statement->pred, $statement->obj);
  173. $rs =& $this->dbConn->execute($sql);
  174. if (!$rs)
  175. $this->dbConn->errorMsg();
  176. }
  177. /**
  178. * Short dump of the DbModel.
  179. *
  180. * @return string
  181. * @access public
  182. */
  183. function toString() {
  184. return 'DbModel[modelURI=' .$this->modelURI .'; baseURI=' .$this->getBaseURI() .'; size=' .$this->size() .']';
  185. }
  186. /**
  187. * Dump of the DbModel including all triples.
  188. *
  189. * @return string
  190. * @access public
  191. */
  192. function toStringIncludingTriples() {
  193. $memModel =& $this->getMemModel();
  194. return $memModel->toStringIncludingTriples();
  195. }
  196. /**
  197. * Create a MemModel containing all the triples of the current DbModel.
  198. *
  199. * @return object MemModel
  200. * @access public
  201. */
  202. function & getMemModel() {
  203. $recordSet = $this->_getRecordSet($this);
  204. return $this->_convertRecordSetToMemModel($recordSet);
  205. }
  206. /**
  207. * Returns the model id
  208. *
  209. * @return int Model id number
  210. * @access public
  211. */
  212. function getModelID()
  213. {
  214. return $this->modelID;
  215. }
  216. /**
  217. * Returns the database connection object
  218. *
  219. * @return ADOdb Database object
  220. * @access public
  221. */
  222. function &getDbConn()
  223. {
  224. return $this->dbConn;
  225. }
  226. /**
  227. * Write the RDF serialization of the _DbModel as HTML.
  228. *
  229. * @access public
  230. */
  231. function writeAsHtml() {
  232. $memModel =& $this->getMemModel();
  233. $memModel->writeAsHtml();
  234. }
  235. /**
  236. * Write the RDF serialization of the DbModel as HTML table.
  237. *
  238. * @access public
  239. */
  240. function writeAsHtmlTable() {
  241. include_once(RDFAPI_INCLUDE_DIR.PACKAGE_UTILITY);
  242. $memModel =& $this->getMemModel();
  243. RDFUtil::writeHTMLTable($memModel);
  244. }
  245. /**
  246. * Write the RDF serialization of the DbModel to string.
  247. *
  248. * @return string
  249. * @access public
  250. */
  251. function writeRdfToString() {
  252. $memModel =& $this->getMemModel();
  253. return $memModel->writeRdfToString();
  254. }
  255. /**
  256. * Saves the RDF,N3 or N-Triple serialization of the DbModel to a file.
  257. * You can decide to which format the model should be serialized by using a
  258. * corresponding suffix-string as $type parameter. If no $type parameter
  259. * is placed this method will serialize the model to XML/RDF format.
  260. * Returns FALSE if the DbModel couldn't be saved to the file.
  261. *
  262. * @access public
  263. * @param string $filename
  264. * @param string $type
  265. * @throws PhpError
  266. * @return boolean
  267. */
  268. function saveAs($filename, $type ='rdf') {
  269. $memModel = $this->getMemModel();
  270. $memModel->saveAs($filename, $type);
  271. }
  272. /**
  273. * Check if the DbModel contains the given statement.
  274. *
  275. * @param object Statement &$statement
  276. * @return boolean
  277. * @access public
  278. */
  279. function contains(&$statement) {
  280. $sql = 'SELECT modelID FROM statements
  281. WHERE modelID = ' .$this->modelID;
  282. $sql .= $this->_createDynSqlPart_SPO($statement->subj, $statement->pred, $statement->obj);
  283. $res =& $this->dbConn->getOne($sql);
  284. if (!$res)
  285. return FALSE;
  286. return TRUE;
  287. }
  288. /**
  289. * Determine if all of the statements in the given model are also contained in this DbModel.
  290. *
  291. * @param object Model &$model
  292. * @return boolean
  293. * @access public
  294. */
  295. function containsAll(&$model) {
  296. if (is_a($model, 'MemModel')) {
  297. foreach($model->triples as $statement)
  298. if(!$this->contains($statement))
  299. return FALSE;
  300. return TRUE;
  301. }
  302. elseif (is_a($model, 'DbModel')) {
  303. $recordSet =& $this->_getRecordSet($model);
  304. while (!$recordSet->EOF) {
  305. if (!$this->_containsRow($recordSet->fields))
  306. return FALSE;
  307. $recordSet->moveNext();
  308. }
  309. return TRUE;
  310. }
  311. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: containsAll): Model expected.';
  312. trigger_error($errmsg, E_USER_ERROR);
  313. }
  314. /**
  315. * Determine if any of the statements in the given model are also contained in this DbModel.
  316. *
  317. * @param object Model &$model
  318. * @return boolean
  319. * @access public
  320. */
  321. function containsAny(&$model) {
  322. if (is_a($model, 'MemModel')) {
  323. foreach($model->triples as $statement)
  324. if($this->contains($statement))
  325. return TRUE;
  326. return FALSE;
  327. }
  328. elseif (is_a($model, 'DbModel')) {
  329. $recordSet =& $this->_getRecordSet($model);
  330. while (!$recordSet->EOF) {
  331. if ($this->_containsRow($recordSet->fields))
  332. return TRUE;
  333. $recordSet->moveNext();
  334. }
  335. return FALSE;
  336. }
  337. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: containsAny): Model expected.';
  338. trigger_error($errmsg, E_USER_ERROR);
  339. }
  340. /**
  341. * General method to search for triples in the DbModel.
  342. * NULL input for any parameter will match anything.
  343. * Example: $result = $m->find( NULL, NULL, $node );
  344. * Finds all triples with $node as object.
  345. *
  346. * @param object Resource $subject
  347. * @param object Resource $predicate
  348. * @param object Node $object
  349. * @return object MemModel
  350. * @throws PhpError
  351. * @throws SqlError
  352. * @access public
  353. */
  354. function find($subject, $predicate, $object) {
  355. if ((!is_a($subject, 'Resource') && $subject != NULL) ||
  356. (!is_a($predicate, 'Resource') && $predicate != NULL) ||
  357. (!is_a($object, 'Node') && $object != NULL)) {
  358. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: find): Parameters must be subclasses of Node or NULL';
  359. trigger_error($errmsg, E_USER_ERROR);
  360. }
  361. // static part of the sql statement
  362. $sql = 'SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  363. FROM statements
  364. WHERE modelID = ' .$this->modelID;
  365. // dynamic part of the sql statement
  366. $sql .= $this->_createDynSqlPart_SPO($subject, $predicate, $object);
  367. // execute the query
  368. $recordSet =& $this->dbConn->execute($sql);
  369. if (!$recordSet)
  370. echo $this->dbConn->errorMsg();
  371. // write the recordSet into memory Model
  372. else
  373. return $this->_convertRecordSetToMemModel($recordSet);
  374. }
  375. /**
  376. * Method to search for triples using Perl-style regular expressions.
  377. * NULL input for any parameter will match anything.
  378. * Example: $result = $m->find_regex( NULL, NULL, $regex );
  379. * Finds all triples where the label of the object node matches
  380. *the regular expression.
  381. * Return an empty MemModel if nothing is found.
  382. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  383. * WARNING: Mhis method loads a DbModel into memory and performs the search
  384. * on a MemModel, which can be slow with large models.
  385. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  386. *
  387. * @param string $subject_regex
  388. * @param string $predicate_regex
  389. * @param string $object_regex
  390. * @return object MemModel
  391. * @throws PhpError
  392. * @throws SqlError
  393. * @access public
  394. */
  395. function findRegex($subject_regex, $predicate_regex, $object_regex) {
  396. $mm =& $this->getMemModel();
  397. return $mm->findRegex($subject_regex, $predicate_regex, $object_regex);
  398. }
  399. /**
  400. * Return all tripels of a certain vocabulary.
  401. * $vocabulary is the namespace of the vocabulary inluding a # : / char at the end.
  402. * e.g. http://www.w3.org/2000/01/rdf-schema#
  403. * Return an empty model if nothing is found.
  404. *
  405. * @param string $vocabulary
  406. * @return object MemModel
  407. * @throws PhpError
  408. * @throws SqlError
  409. * @access public
  410. */
  411. function findVocabulary($vocabulary) {
  412. $sql = "SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  413. FROM statements
  414. WHERE modelID = " .$this->modelID ."
  415. AND predicate LIKE '" .$vocabulary ."%'";
  416. $recordSet =& $this->dbConn->execute($sql);
  417. if (!$recordSet)
  418. echo $this->dbConn->errorMsg();
  419. // write the recordSet into memory Model
  420. else
  421. return $this->_convertRecordSetToMemModel($recordSet);
  422. }
  423. /**
  424. * Search for triples and return the first matching statement.
  425. * NULL input for any parameter will match anything.
  426. * Return an NULL if nothing is found.
  427. * You can set an search offset with $offset.
  428. *
  429. * @param object Resource $subject
  430. * @param object Resource $predicate
  431. * @param object Node $object
  432. * @param integer $offset
  433. * @return object Statement
  434. * @throws PhpError
  435. * @throws SqlError
  436. * @access public
  437. */
  438. function findFirstMatchingStatement($subject, $predicate, $object, $offset = -1) {
  439. if ((!is_a($subject, 'Resource') && $subject != NULL) ||
  440. (!is_a($predicate, 'Resource') && $predicate != NULL) ||
  441. (!is_a($object, 'Node') && $object != NULL)) {
  442. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: find): Parameters must be subclasses of Node or NULL';
  443. trigger_error($errmsg, E_USER_ERROR);
  444. }
  445. // static part of the sql statement
  446. $sql = 'SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  447. FROM statements
  448. WHERE modelID = ' .$this->modelID;
  449. // dynamic part of the sql statement
  450. $sql .= $this->_createDynSqlPart_SPO($subject, $predicate, $object);
  451. // execute the query
  452. $recordSet =& $this->dbConn->selectLimit($sql,1,($offset));
  453. if (!$recordSet)
  454. echo $this->dbConn->errorMsg();
  455. else {
  456. if (!$recordSet->fields)
  457. return NULL;
  458. else {
  459. $memModel = $this->_convertRecordSetToMemModel($recordSet);
  460. return $memModel->triples[0];
  461. }
  462. }
  463. }
  464. /**
  465. * Search for triples and return the number of matches.
  466. * NULL input for any parameter will match anything.
  467. *
  468. * @param object Resource $subject
  469. * @param object Resource $predicate
  470. * @param object Node $object
  471. * @return integer
  472. * @throws PhpError
  473. * @throws SqlError
  474. * @access public
  475. */
  476. function findCount($subject, $predicate, $object) {
  477. if ((!is_a($subject, 'Resource') && $subject != NULL) ||
  478. (!is_a($predicate, 'Resource') && $predicate != NULL) ||
  479. (!is_a($object, 'Node') && $object != NULL)) {
  480. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: find): Parameters must be subclasses of Node or NULL';
  481. trigger_error($errmsg, E_USER_ERROR);
  482. }
  483. // static part of the sql statement
  484. $sql = 'SELECT COUNT(*)
  485. FROM statements
  486. WHERE modelID = ' .$this->modelID;
  487. // dynamic part of the sql statement
  488. $sql .= $this->_createDynSqlPart_SPO($subject, $predicate, $object);
  489. // execute the query
  490. $recordSet =& $this->dbConn->execute($sql);
  491. if (!$recordSet)
  492. echo $this->dbConn->errorMsg();
  493. else
  494. return $recordSet->fields[0];
  495. }
  496. /**
  497. * Perform an RDQL query on this DbModel.
  498. * This method returns an associative array of variable bindings.
  499. * The values of the query variables can either be RAP's objects (instances of Node)
  500. * if $returnNodes set to TRUE, or their string serialization.
  501. *
  502. * @access public
  503. * @param string $queryString
  504. * @param boolean $returnNodes
  505. * @return array [][?VARNAME] = object Node (if $returnNodes = TRUE)
  506. * OR array [][?VARNAME] = string
  507. *
  508. */
  509. function rdqlQuery($queryString, $returnNodes = TRUE) {
  510. require_once(RDFAPI_INCLUDE_DIR.PACKAGE_RDQL);
  511. $parser = new RdqlParser();
  512. $parsedQuery =& $parser->parseQuery($queryString);
  513. // this method can only query this DbModel
  514. // if another model was specified in the from clause throw an error
  515. if (isset($parsedQuery['sources'][0]))
  516. if($parsedQuery['sources'][0] != $this->modelURI) {
  517. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: rdqlQuery):';
  518. $errmsg .= ' this method can only query this DbModel';
  519. trigger_error($errmsg, E_USER_ERROR);
  520. }
  521. $engine = new RdqlDbEngine();
  522. $res =& $engine->queryModel($this, $parsedQuery, $returnNodes);
  523. return $res;
  524. }
  525. /**
  526. * Perform an RDQL query on this DBModel.
  527. * This method returns an RdqlResultIterator of variable bindings.
  528. * The values of the query variables can either be RAP's objects (instances of Node)
  529. * if $returnNodes set to TRUE, or their string serialization.
  530. *
  531. * @access public
  532. * @param string $queryString
  533. * @param boolean $returnNodes
  534. * @return object RdqlResultIterator = with values as object Node (if $returnNodes = TRUE)
  535. * OR object RdqlResultIterator = with values as strings if (if $returnNodes = FALSE)
  536. *
  537. */
  538. function rdqlQueryAsIterator($queryString, $returnNodes = TRUE) {
  539. require_once(RDFAPI_INCLUDE_DIR.PACKAGE_RDQL);
  540. return new RdqlResultIterator($this->rdqlQuery($queryString, $returnNodes));
  541. }
  542. /**
  543. * General method to replace nodes of a DbModel.
  544. * NULL input for any parameter will match nothing.
  545. * Example: $m->replace($resource, NULL, $node, $replacement);
  546. * Replaces all $node objects beeing subject or object in
  547. * any triple of the model with the $replacement node.
  548. * Throw an error in case of a paramter mismatch.
  549. *
  550. * @param object Resource $subject
  551. * @param object Resource $predicate
  552. * @param object Node $object
  553. * @param object Node $replacement
  554. * @throws PhpError
  555. * @throws SqlError
  556. * @access public
  557. */
  558. function replace($subject, $predicate, $object, $replacement) {
  559. // check the correctness of the passed parameters
  560. if ( ((!is_a($subject, 'Resource') && $subject != NULL) ||
  561. (!is_a($predicate, 'Resource') && $predicate != NULL) ||
  562. (!is_a($object, 'Node') && $object != NULL)) ||
  563. (($subject != NULL && is_a($replacement, 'Literal')) ||
  564. ($predicate != NULL && (is_a($replacement, 'Literal') ||
  565. is_a($replacement, 'BlankNode')))) )
  566. {
  567. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: find): Parameter mismatch';
  568. trigger_error($errmsg, E_USER_ERROR);
  569. }
  570. if (!(!$subject && !$predicate && !$object)) {
  571. // create an update sql statement
  572. $comma = '';
  573. $sql = 'UPDATE statements
  574. SET ';
  575. if ($subject) {
  576. $sql .= " subject ='" .$replacement->getLabel() ."', "
  577. ." subject_is='" .$this->_getNodeFlag($replacement) ."' ";
  578. $comma = ',';
  579. }
  580. if ($predicate) {
  581. $sql .= $comma ." predicate='" .$replacement->getLabel() ."' ";
  582. $comma = ',';
  583. }
  584. if ($object) {
  585. $quotedObject = $this->dbConn->qstr($replacement->getLabel());
  586. $sql .= $comma .' object=' .$quotedObject
  587. .", object_is='" .$this->_getNodeFlag($replacement) ."' ";
  588. if (is_a($replacement, 'Literal')) {
  589. $sql .= ", l_language='" .$replacement->getLanguage() ."' "
  590. .", l_datatype='" .$replacement->getDataType() ."' ";
  591. }
  592. }
  593. $sql .= 'WHERE modelID = ' .$this->modelID;
  594. $sql .= $this->_createDynSqlPart_SPO($subject, $predicate, $object);
  595. // execute the query
  596. $rs =& $this->dbConn->execute($sql);
  597. if (!$rs)
  598. echo $this->dbConn->errorMsg();
  599. }
  600. }
  601. /**
  602. * Check if two models are equal.
  603. * Two models are equal if and only if the two RDF graphs they represent are isomorphic.
  604. *
  605. * Warning: This method doesn't work correct with models where the same blank node has different
  606. * identifiers in the two models. We will correct this in a future version.
  607. *
  608. * @param object model &$that
  609. * @return boolean
  610. * @throws PhpError
  611. * @access public
  612. */
  613. function equals(&$that) {
  614. if (!is_a($that, 'Model')) {
  615. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: equals): Model expected.';
  616. trigger_error($errmsg, E_USER_ERROR);
  617. }
  618. if ($this->size() != $that->size())
  619. return FALSE;
  620. include_once(RDFAPI_INCLUDE_DIR. "util/ModelComparator.php");
  621. return ModelComparator::compare($this,$that);
  622. }
  623. /**
  624. * Return a new MemModel that is the set-union the model with another model.
  625. *
  626. * The result of taking the set-union of two or more RDF graphs (i.e. sets of triples)
  627. * is another graph, which we will call the merge of the graphs.
  628. * Each of the original graphs is a subgraph of the merged graph. Notice that when forming
  629. * a merged graph, two occurrences of a given uriref or literal as nodes in two different
  630. * graphs become a single node in the union graph (since by definition they are the same
  631. * uriref or literal) but blank nodes are not 'merged' in this way; and arcs are of course
  632. * never merged. In particular, this means that every blank node in a merged graph can be
  633. * identified as coming from one particular graph in the original set of graphs.
  634. *
  635. * Notice that one does not, in general, obtain the merge of a set of graphs by concatenating
  636. * their corresponding N-triples documents and constructing the graph described by the merged
  637. * document, since if some of the documents use the same node identifiers, the merged document
  638. * will describe a graph in which some of the blank nodes have been 'accidentally' merged.
  639. * To merge Ntriples documents it is necessary to check if the same nodeID is used in two or
  640. * more documents, and to replace it with a distinct nodeID in each of them, before merging the
  641. * documents. (Not implemented yet !!!!!!!!!!!)
  642. *
  643. * @param object Model $model
  644. * @return object MemModel
  645. * @throws PhpError
  646. * @access public
  647. *
  648. */
  649. function & unite(&$model) {
  650. if (!is_a($model, 'Model')) {
  651. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: unite): Model expected.';
  652. trigger_error($errmsg, E_USER_ERROR);
  653. }
  654. if (is_a($model, 'MemModel')) {
  655. $thisModel =& $this->getMemModel();
  656. return $thisModel->unite($model);
  657. }
  658. elseif (is_a($model, 'DbModel')) {
  659. $thisModel =& $this->getMemModel();
  660. $thatModel =& $model->getMemModel();
  661. return $thisModel->unite($thatModel);
  662. }
  663. }
  664. /**
  665. * Return a new MemModel that is the subtraction of another model from this DbModel.
  666. *
  667. * @param object Model $model
  668. * @return object MemModel
  669. * @throws PhpError
  670. * @access public
  671. */
  672. function & subtract(&$model) {
  673. if (!is_a($model, 'Model')) {
  674. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: subtract): Model expected.';
  675. trigger_error($errmsg, E_USER_ERROR);
  676. }
  677. if (is_a($model, 'MemModel')) {
  678. $thisModel =& $this->getMemModel();
  679. return $thisModel->subtract($model);
  680. }
  681. elseif (is_a($model, 'DbModel')) {
  682. $thisModel =& $this->getMemModel();
  683. $thatModel =& $model->getMemModel();
  684. return $thisModel->subtract($thatModel);
  685. }
  686. }
  687. /**
  688. * Return a new MemModel containing all the statements which are in both
  689. * this model and the given model.
  690. *
  691. * @param object Model $model
  692. * @return object MemModel
  693. * @throws PhpError
  694. * @access public
  695. */
  696. function & intersect(&$model) {
  697. if (is_a($model, 'MemModel')) {
  698. $thisModel =& $this->getMemModel();
  699. return $thisModel->intersect($model);
  700. }
  701. elseif (is_a($model, 'DbModel')) {
  702. $thisModel =& $this->getMemModel();
  703. $thatModel =& $model->getMemModel();
  704. return $thisModel->intersect($thatModel);
  705. }
  706. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: intersect: Model expected.';
  707. trigger_error($errmsg, E_USER_ERROR);
  708. }
  709. /**
  710. * Add the given model to this DbModel.
  711. * This function monitors for SQL errors, and will commit if no errors have occured,
  712. * otherwise it will rollback.
  713. * If any statement of the model to be added to this model contains a blankNode
  714. * with an identifier already existing in this model, a new blankNode is generated.
  715. *
  716. * @param object Model $model
  717. * @throws PhpError
  718. * @access public
  719. */
  720. function addModel(&$model) {
  721. if (!is_a($model, 'Model')) {
  722. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: addModel): Model expected.';
  723. trigger_error($errmsg, E_USER_ERROR);
  724. }
  725. $blankNodes_tmp = array();
  726. if (is_a($model, 'MemModel')) {
  727. $this->dbConn->startTrans();
  728. foreach ($model->triples as $statement)
  729. $this->_addStatementFromAnotherModel($statement, $blankNodes_tmp);
  730. $this->addParsedNamespaces($model->getParsedNamespaces());
  731. $this->dbConn->completeTrans();
  732. }
  733. elseif (is_a($model, 'DbModel')) {
  734. $this->dbConn->startTrans();
  735. $memModel =& $model->getMemModel();
  736. foreach($memModel->triples as $statement)
  737. $this->_addStatementFromAnotherModel($statement, $blankNodes_tmp);
  738. $this->addParsedNamespaces($model->getParsedNamespaces());
  739. $this->dbConn->completeTrans();
  740. }
  741. }
  742. /**
  743. * Reify the DbModel.
  744. * Return a new MemModel that contains the reifications of all statements of this DbModel.
  745. *
  746. * @return object MemModel
  747. * @access public
  748. */
  749. function & reify() {
  750. $memModel =& $this->getMemModel();
  751. return $memModel->reify();
  752. }
  753. /**
  754. * Remove this DbModel from database and clean up.
  755. * This function monitors for SQL errors, and will commit if no errors have occured,
  756. * otherwise it will rollback.
  757. *
  758. * @throws SqlError
  759. * @access public
  760. */
  761. function delete() {
  762. $this->dbConn->startTrans();
  763. $this->dbConn->execute('DELETE FROM models
  764. WHERE modelID=' .$this->modelID);
  765. $this->dbConn->execute('DELETE FROM statements
  766. WHERE modelID=' .$this->modelID);
  767. if (!$this->dbConn->completeTrans())
  768. echo $this->dbConn->errorMsg();
  769. else
  770. $this->close();
  771. }
  772. /**
  773. * Close this DbModel
  774. *
  775. * @access public
  776. */
  777. function close() {
  778. unset($this);
  779. }
  780. // =============================================================================
  781. // **************************** private methods ********************************
  782. // =============================================================================
  783. /**
  784. * If the URI doesn't end with # : or /, then a # is added to the URI.
  785. * Used at setting the baseURI of this DbModel.
  786. *
  787. * @param string $uri
  788. * @return string
  789. * @access private
  790. */
  791. function _checkBaseURI($uri) {
  792. if ($uri != NULL) {
  793. $c = substr($uri, strlen($uri)-1 ,1);
  794. if (!($c=='#' || $c==':' || $c=='/' || $c=="\\"))
  795. $uri .= '#';
  796. }
  797. return $uri;
  798. }
  799. /**'
  800. * Return the flag of the Node object.
  801. * r - Resource, b - BlankNode, l - Literal
  802. *
  803. * @param object Node $object
  804. * @return string
  805. * @access private
  806. */
  807. function _getNodeFlag($object) {
  808. return is_a($object,'BlankNode')?'b':(is_a($object,'Resource')?'r':'l');
  809. }
  810. /**
  811. * Convert an ADORecordSet to a memory Model.
  812. *
  813. * Every successful database query returns an ADORecordSet object which is actually
  814. * a cursor that holds the current row in the array fields[].
  815. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  816. * !!! This method can only be applied to a RecordSet with array fields[]
  817. * !!! containing a representation of the database table: statements,
  818. * !!! with an index corresponding to following table columns:
  819. * !!! [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  820. * !!! [4] - l_datatype, [5] - subject_is, [6] - object_is
  821. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  822. *
  823. * @param object ADORecordSet
  824. * @return object MemModel
  825. * @access private
  826. */
  827. function _convertRecordSetToMemModel(&$recordSet) {
  828. $res = new MemModel($this->baseURI);
  829. while (!$recordSet->EOF) {
  830. // subject
  831. if ($recordSet->fields[5] == 'r')
  832. $sub = new Resource($recordSet->fields[0]);
  833. else
  834. $sub = new BlankNode($recordSet->fields[0]);
  835. // predicate
  836. $pred = new Resource($recordSet->fields[1]);
  837. // object
  838. if ($recordSet->fields[6] == 'r')
  839. $obj = new Resource($recordSet->fields[2]);
  840. elseif ($recordSet->fields[6] == 'b')
  841. $obj = new BlankNode($recordSet->fields[2]);
  842. else {
  843. $obj = new Literal($recordSet->fields[2], $recordSet->fields[3]);
  844. if ($recordSet->fields[4])
  845. $obj->setDatatype($recordSet->fields[4]);
  846. }
  847. $statement = new Statement($sub, $pred, $obj);
  848. $res->add($statement);
  849. $recordSet->moveNext();
  850. }
  851. $res->addParsedNamespaces($this->getParsedNamespaces());
  852. return $res;
  853. }
  854. /**
  855. * Create the dynamic part of an sql statement selecting triples with the
  856. * given parameters ($subject, $predicate, $object).
  857. *
  858. * @param object Resource $subject
  859. * @param object Resource $predicate
  860. * @param object Node $object
  861. * @return string
  862. * @access private
  863. */
  864. function _createDynSqlPart_SPO($subject, $predicate, $object) {
  865. // conditions derived from the parameters passed to the function
  866. $subject_is=is_a($subject,'BlankNode')?'b':(is_a($subject,'Resource')?'r':'l');
  867. $sql='';
  868. if ($subject != NULL)
  869. $sql .= " AND subject='" .$subject->getLabel() ."'
  870. AND subject_is='" .$subject_is ."'";
  871. if ($predicate != NULL)
  872. $sql .= " AND predicate='" .$predicate->getLabel() ."'";
  873. if ($object != NULL) {
  874. $object_is = is_a($object,'BlankNode')?'b':(is_a($object,'Resource')?'r':'l');
  875. if (is_a($object, 'Resource'))
  876. $sql .= " AND object='" .$object->getLabel() ."'
  877. AND object_is ='" .$object_is ."'";
  878. else {
  879. $quotedLiteral = $this->dbConn->qstr($object->getLabel());
  880. $sql .= " AND object=" .$quotedLiteral ."
  881. AND l_language='" .$object->getLanguage() ."'
  882. AND l_datatype='" .$object->getDataType() ."'
  883. AND object_is ='" .$object_is ."'";
  884. }
  885. }
  886. return $sql;
  887. }
  888. /**
  889. * Get an ADORecordSet with array fields[] containing a representation of
  890. * the given DbModel stored in the table: statements, with an index corresponding
  891. * to following table columns:
  892. * [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  893. * [4] - l_datatype, [5] - subject_is, [6] - object_is
  894. * (This method operates on data from a DbModel without loading it into a memory model
  895. * in order to save resources and improve speed).
  896. *
  897. * @param object DbModel $DbModel
  898. * @return object ADORecordSet
  899. * @access private
  900. */
  901. function _getRecordSet (&$dbModel) {
  902. $sql = 'SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  903. FROM statements
  904. WHERE modelID = ' .$dbModel->modelID;
  905. return $recordSet =& $this->dbConn->execute($sql);
  906. }
  907. /**
  908. * Check if this DbModel contains the given row from the array fields[] of an ADORecordSet
  909. * The array index corresponds to following table columns:
  910. * [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  911. * [4] - l_datatype, [5] - subject_is, [6] - object_is
  912. *
  913. * @param array $row
  914. * @return boolean
  915. * @access private
  916. */
  917. function _containsRow ($row) {
  918. $quotedObject = $this->dbConn->qstr($row[2]);
  919. $sql = "SELECT modelID FROM statements
  920. WHERE modelID = " .$this->modelID ."
  921. AND subject ='" .$row[0] ."'
  922. AND predicate ='" .$row[1] ."'
  923. AND object =" .$quotedObject ."
  924. AND l_language='" .$row[3] ."'
  925. AND l_datatype='" .$row[4] ."'
  926. AND subject_is='" .$row[5] ."'
  927. AND object_is='" .$row[6] ."'";
  928. $res =& $this->dbConn->getOne($sql);
  929. if (!$res)
  930. return FALSE;
  931. return TRUE;
  932. }
  933. /**
  934. * Returns the models namespaces.
  935. *
  936. * @author Tobias Gau?<tobias.gauss@web.de>
  937. * @access public
  938. * @return Array
  939. */
  940. function getParsedNamespaces(){
  941. $sql = "SELECT * FROM namespaces
  942. WHERE modelID = " .$this->modelID;
  943. $temp=false;
  944. $res = $this->dbConn->execute($sql);
  945. if($res){
  946. while (!$res->EOF) {
  947. $temp[$res->fields[1]]=$res->fields[2];
  948. $res->moveNext();
  949. }
  950. }
  951. return $temp;
  952. }
  953. /**
  954. * Adds the namespaces to the model. This method is called by
  955. * the parser. !!!! addParsedNamespaces() not overwrites manual
  956. * added namespaces in the model !!!!
  957. *
  958. * @author Tobias Gau?<tobias.gauss@web.de>
  959. * @access public
  960. * @param Array $newNs
  961. */
  962. function addParsedNamespaces($newNs){
  963. if($newNs)
  964. foreach($newNs as $namespace => $prefix){
  965. $this->addNamespace($prefix, $namespace);
  966. }
  967. }
  968. /**
  969. * Adds a namespace and prefix to the model.
  970. *
  971. * @author Tobias Gau?<tobias.gauss@web.de>
  972. * @access public
  973. * @param String $prefix, String $nmsp
  974. */
  975. function addNamespace($prefix,$nmsp){
  976. if($nmsp != '' && $prefix !=''){
  977. if($this->_checkNamespace($nmsp)){
  978. $sql = "UPDATE namespaces SET prefix='".$prefix."' WHERE
  979. modelID=".$this->modelID." AND namespace='".$nmsp."'";
  980. }else{
  981. $sql = "INSERT INTO namespaces
  982. (modelID, namespace, prefix)
  983. VALUES
  984. (" .$this->modelID .","
  985. ."'" .$nmsp ."',"
  986. ."'" .$prefix."')";
  987. }
  988. $rs =& $this->dbConn->execute($sql);
  989. if (!$rs)
  990. $this->dbConn->errorMsg();
  991. }
  992. }
  993. /**
  994. * checks if a namespace is already in the model.
  995. *
  996. * @author Tobias Gau?<tobias.gauss@web.de>
  997. * @access private
  998. * @param Array $newNs
  999. */
  1000. function _checkNamespace($nmsp){
  1001. $res = true;
  1002. $sql = "SELECT * FROM namespaces
  1003. WHERE modelID = " .$this->modelID." AND
  1004. namespace='".$nmsp."'" ;
  1005. $rs =& $this->dbConn->execute($sql);
  1006. if (!$rs){
  1007. $this->dbConn->errorMsg();
  1008. }else{
  1009. if($rs->fields == false)
  1010. $res = false;
  1011. }
  1012. return $res;
  1013. }
  1014. /**
  1015. * Returns a FindIterator for traversing the MemModel.
  1016. * @access public
  1017. * @return object FindIterator
  1018. */
  1019. function & iterFind($sub=null,$pred=null,$obj=null) {
  1020. // Import Package Utility
  1021. include_once(RDFAPI_INCLUDE_DIR.PACKAGE_UTILITY);
  1022. $if = new IterFind($this,$sub,$pred,$obj);
  1023. return $if;
  1024. }
  1025. /**
  1026. * removes a single namespace from the model
  1027. *
  1028. * @author Tobias Gau?<tobias.gauss@web.de>
  1029. * @access public
  1030. * @param String $nmsp
  1031. */
  1032. function removeNamespace($nmsp){
  1033. $sql = 'DELETE FROM namespaces
  1034. WHERE modelID=' .$this->modelID." AND namespace='".$nmsp."'";
  1035. $rs =& $this->dbConn->execute($sql);
  1036. if (!$rs)
  1037. $this->dbConn->errorMsg();
  1038. }
  1039. /**
  1040. * Add the given row from the array fields[] of an ADORecordSet to this DbModel
  1041. * The array index corresponds to following table columns:
  1042. * [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  1043. * [4] - l_datatype, [5] - subject_is, [6] - object_is
  1044. *
  1045. * @param array $row
  1046. * @throws SqlError
  1047. * @access private
  1048. *
  1049. function _insertRow ($row) {
  1050. $quotedObject = $this->dbConn->qstr($row[2]);
  1051. $sql = "INSERT INTO statements VALUES
  1052. (" .$this->modelID .","
  1053. ."'" .$row[0] ."',"
  1054. ."'" .$row[1] ."',"
  1055. ."" .$quotedObject .","
  1056. ."'" .$row[3] ."',"
  1057. ."'" .$row[4] ."',"
  1058. ."'" .$row[5] ."',"
  1059. ."'" .$row[6] ."')";
  1060. $rs =& $this->dbConn->execute($sql);
  1061. if (!$rs)
  1062. $this->dbConn->errorMsg();
  1063. }
  1064. */
  1065. } // end: Class DbModel
  1066. ?>