PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/tdt/core/model/semantics/rdfapi-php/api/model/DbModel.php

https://github.com/oSoc13/tdt-core
PHP | 1243 lines | 534 code | 166 blank | 543 comment | 125 complexity | 63ec34b13454d6d0cbabcc66e293c7fa MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1
  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 533 2007-08-16 09:32:03Z cweiske $
  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. private $dbConn;
  28. /**
  29. * Unique model URI.
  30. * Used to identify the DbModel.
  31. *
  32. * @var string
  33. * @access private
  34. */
  35. protected $modelURI;
  36. /**
  37. * Database internal modelID.
  38. * Used to avoid JOINs.
  39. *
  40. * @var string
  41. * @access private
  42. */
  43. protected $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. public 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. public 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. public 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. public 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. public 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->getSubject());
  115. $sql = "INSERT INTO statements
  116. (modelID, subject, predicate, object, l_language, l_datatype, subject_is, object_is)
  117. VALUES
  118. (" . $this->modelID . ","
  119. . $this->dbConn->qstr($statement->getLabelSubject()) . ","
  120. . $this->dbConn->qstr($statement->getLabelPredicate()) . ",";
  121. if (is_a($statement->getObject(), 'Literal')) {
  122. $quotedLiteral = $this->dbConn->qstr($statement->getObject()->getLabel());
  123. $sql .= $quotedLiteral . ","
  124. . "'" . $statement->getObject()->getLanguage() . "',"
  125. . "'" . $statement->getObject()->getDatatype() . "',"
  126. . "'" . $subject_is . "',"
  127. . "'l')";
  128. } else {
  129. $object_is = $this->_getNodeFlag($statement->getObject());
  130. $sql .= $this->dbConn->qstr($statement->getObject()->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. public 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. public 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->getSubject(), $statement->getPredicate(), $statement->getObject());
  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. public 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. public 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. public function getMemModel() {
  203. $recordSet = $this->_getRecordSet($this);
  204. $m = $this->_convertRecordSetToMemModel($recordSet);
  205. return $m;
  206. }
  207. /**
  208. * Returns the model id
  209. *
  210. * @return int Model id number
  211. * @access public
  212. */
  213. public function getModelID() {
  214. return $this->modelID;
  215. }
  216. /**
  217. * Returns the database connection object
  218. *
  219. * @return ADOdb Database object
  220. * @access public
  221. */
  222. public function getDbConn() {
  223. return $this->dbConn;
  224. }
  225. /**
  226. * Write the RDF serialization of the _DbModel as HTML.
  227. *
  228. * @access public
  229. */
  230. public function writeAsHtml() {
  231. $memModel = & $this->getMemModel();
  232. $memModel->writeAsHtml();
  233. }
  234. /**
  235. * Write the RDF serialization of the DbModel as HTML table.
  236. *
  237. * @access public
  238. */
  239. public function writeAsHtmlTable() {
  240. include_once(RDFAPI_INCLUDE_DIR . PACKAGE_UTILITY);
  241. $memModel = $this->getMemModel();
  242. RDFUtil::writeHTMLTable($memModel);
  243. }
  244. /**
  245. * Write the RDF serialization of the DbModel to string.
  246. *
  247. * @return string
  248. * @access public
  249. */
  250. public function writeRdfToString() {
  251. $memModel = $this->getMemModel();
  252. return $memModel->writeRdfToString();
  253. }
  254. /**
  255. * Saves the RDF,N3 or N-Triple serialization of the DbModel to a file.
  256. * You can decide to which format the model should be serialized by using a
  257. * corresponding suffix-string as $type parameter. If no $type parameter
  258. * is placed this method will serialize the model to XML/RDF format.
  259. * Returns FALSE if the DbModel couldn't be saved to the file.
  260. *
  261. * @access public
  262. * @param string $filename
  263. * @param string $type
  264. * @throws PhpError
  265. * @return boolean
  266. */
  267. public function saveAs($filename, $type = 'rdf') {
  268. $memModel = $this->getMemModel();
  269. $memModel->saveAs($filename, $type);
  270. }
  271. /**
  272. * Check if the DbModel contains the given statement.
  273. *
  274. * @param object Statement &$statement
  275. * @return boolean
  276. * @access public
  277. */
  278. public function contains(&$statement) {
  279. $sql = 'SELECT modelID FROM statements
  280. WHERE modelID = ' . $this->modelID;
  281. $sql .= $this->_createDynSqlPart_SPO($statement->getSubject(), $statement->getPredicate(), $statement->getObject());
  282. $res = & $this->dbConn->getOne($sql);
  283. if (!$res)
  284. return FALSE;
  285. return TRUE;
  286. }
  287. /**
  288. * Determine if all of the statements in the given model are also contained in this DbModel.
  289. *
  290. * @param object Model &$model
  291. * @return boolean
  292. * @access public
  293. */
  294. public function containsAll(&$model) {
  295. if (is_a($model, 'MemModel')) {
  296. foreach ($model->triples as $statement)
  297. if (!$this->contains($statement))
  298. return FALSE;
  299. return TRUE;
  300. }
  301. elseif (is_a($model, 'DbModel')) {
  302. $recordSet = & $this->_getRecordSet($model);
  303. while (!$recordSet->EOF) {
  304. if (!$this->_containsRow($recordSet->fields))
  305. return FALSE;
  306. $recordSet->moveNext();
  307. }
  308. return TRUE;
  309. }
  310. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: containsAll): Model expected.';
  311. trigger_error($errmsg, E_USER_ERROR);
  312. }
  313. /**
  314. * Determine if any of the statements in the given model are also contained in this DbModel.
  315. *
  316. * @param object Model &$model
  317. * @return boolean
  318. * @access public
  319. */
  320. public function containsAny(&$model) {
  321. if (is_a($model, 'MemModel')) {
  322. foreach ($model->triples as $statement)
  323. if ($this->contains($statement))
  324. return TRUE;
  325. return FALSE;
  326. }
  327. elseif (is_a($model, 'DbModel')) {
  328. $recordSet = & $this->_getRecordSet($model);
  329. while (!$recordSet->EOF) {
  330. if ($this->_containsRow($recordSet->fields))
  331. return TRUE;
  332. $recordSet->moveNext();
  333. }
  334. return FALSE;
  335. }
  336. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: containsAny): Model expected.';
  337. trigger_error($errmsg, E_USER_ERROR);
  338. }
  339. /**
  340. * General method to search for triples in the DbModel.
  341. * NULL input for any parameter will match anything.
  342. * Example: $result = $m->find( NULL, NULL, $node );
  343. * Finds all triples with $node as object.
  344. *
  345. * @param object Resource $subject
  346. * @param object Resource $predicate
  347. * @param object Node $object
  348. * @return object MemModel
  349. * @throws PhpError
  350. * @throws SqlError
  351. * @access public
  352. */
  353. public function find($subject, $predicate, $object) {
  354. if ((!is_a($subject, 'Resource') && $subject != NULL) ||
  355. (!is_a($predicate, 'Resource') && $predicate != NULL) ||
  356. (!is_a($object, 'Node') && $object != NULL)) {
  357. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: find): Parameters must be subclasses of Node or NULL';
  358. trigger_error($errmsg, E_USER_ERROR);
  359. }
  360. // static part of the sql statement
  361. $sql = 'SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  362. FROM statements
  363. WHERE modelID = ' . $this->modelID;
  364. // dynamic part of the sql statement
  365. $sql .= $this->_createDynSqlPart_SPO($subject, $predicate, $object);
  366. // execute the query
  367. $recordSet = & $this->dbConn->execute($sql);
  368. if (!$recordSet)
  369. echo $this->dbConn->errorMsg();
  370. // write the recordSet into memory Model
  371. else
  372. return $this->_convertRecordSetToMemModel($recordSet);
  373. }
  374. /**
  375. * Method to search for triples using Perl-style regular expressions.
  376. * NULL input for any parameter will match anything.
  377. * Example: $result = $m->find_regex( NULL, NULL, $regex );
  378. * Finds all triples where the label of the object node matches
  379. * the regular expression.
  380. * Return an empty MemModel if nothing is found.
  381. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  382. * WARNING: Mhis method loads a DbModel into memory and performs the search
  383. * on a MemModel, which can be slow with large models.
  384. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  385. *
  386. * @param string $subject_regex
  387. * @param string $predicate_regex
  388. * @param string $object_regex
  389. * @return object MemModel
  390. * @throws PhpError
  391. * @throws SqlError
  392. * @access public
  393. */
  394. public function findRegex($subject_regex, $predicate_regex, $object_regex) {
  395. $mm = & $this->getMemModel();
  396. return $mm->findRegex($subject_regex, $predicate_regex, $object_regex);
  397. }
  398. /**
  399. * Return all tripels of a certain vocabulary.
  400. * $vocabulary is the namespace of the vocabulary inluding a # : / char at the end.
  401. * e.g. http://www.w3.org/2000/01/rdf-schema#
  402. * Return an empty model if nothing is found.
  403. *
  404. * @param string $vocabulary
  405. * @return object MemModel
  406. * @throws PhpError
  407. * @throws SqlError
  408. * @access public
  409. */
  410. public function findVocabulary($vocabulary) {
  411. $sql = "SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  412. FROM statements
  413. WHERE modelID = " . $this->modelID . "
  414. AND predicate LIKE '" . $vocabulary . "%'";
  415. $recordSet = & $this->dbConn->execute($sql);
  416. if (!$recordSet)
  417. echo $this->dbConn->errorMsg();
  418. // write the recordSet into memory Model
  419. else
  420. return $this->_convertRecordSetToMemModel($recordSet);
  421. }
  422. /**
  423. * Search for triples and return the first matching statement.
  424. * NULL input for any parameter will match anything.
  425. * Return an NULL if nothing is found.
  426. * You can set an search offset with $offset.
  427. *
  428. * @param object Resource $subject
  429. * @param object Resource $predicate
  430. * @param object Node $object
  431. * @param integer $offset
  432. * @return object Statement
  433. * @throws PhpError
  434. * @throws SqlError
  435. * @access public
  436. */
  437. public function findFirstMatchingStatement($subject, $predicate, $object, $offset = -1) {
  438. if ((!is_a($subject, 'Resource') && $subject != NULL) ||
  439. (!is_a($predicate, 'Resource') && $predicate != NULL) ||
  440. (!is_a($object, 'Node') && $object != NULL)) {
  441. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: find): Parameters must be subclasses of Node or NULL';
  442. trigger_error($errmsg, E_USER_ERROR);
  443. }
  444. // static part of the sql statement
  445. $sql = 'SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  446. FROM statements
  447. WHERE modelID = ' . $this->modelID;
  448. // dynamic part of the sql statement
  449. $sql .= $this->_createDynSqlPart_SPO($subject, $predicate, $object);
  450. // execute the query
  451. $recordSet = & $this->dbConn->selectLimit($sql, 1, ($offset));
  452. if (!$recordSet)
  453. echo $this->dbConn->errorMsg();
  454. else {
  455. if (!$recordSet->fields)
  456. return NULL;
  457. else {
  458. $memModel = $this->_convertRecordSetToMemModel($recordSet);
  459. $triples = $memModel->triples;
  460. return $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. public 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. public 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. public 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. public 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. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: find): Parameter mismatch';
  567. trigger_error($errmsg, E_USER_ERROR);
  568. }
  569. if (!(!$subject && !$predicate && !$object)) {
  570. // create an update sql statement
  571. $comma = '';
  572. $sql = 'UPDATE statements
  573. SET ';
  574. if ($subject) {
  575. $sql .= " subject ='" . $replacement->getLabel() . "', "
  576. . " subject_is='" . $this->_getNodeFlag($replacement) . "' ";
  577. $comma = ',';
  578. }
  579. if ($predicate) {
  580. $sql .= $comma . " predicate='" . $replacement->getLabel() . "' ";
  581. $comma = ',';
  582. }
  583. if ($object) {
  584. $quotedObject = $this->dbConn->qstr($replacement->getLabel());
  585. $sql .= $comma . ' object=' . $quotedObject
  586. . ", object_is='" . $this->_getNodeFlag($replacement) . "' ";
  587. if (is_a($replacement, 'Literal')) {
  588. $sql .= ", l_language='" . $replacement->getLanguage() . "' "
  589. . ", l_datatype='" . $replacement->getDataType() . "' ";
  590. }
  591. }
  592. $sql .= 'WHERE modelID = ' . $this->modelID;
  593. $sql .= $this->_createDynSqlPart_SPO($subject, $predicate, $object);
  594. // execute the query
  595. $rs = & $this->dbConn->execute($sql);
  596. if (!$rs)
  597. echo $this->dbConn->errorMsg();
  598. }
  599. }
  600. /**
  601. * Check if two models are equal.
  602. * Two models are equal if and only if the two RDF graphs they represent are isomorphic.
  603. *
  604. * Warning: This method doesn't work correct with models where the same blank node has different
  605. * identifiers in the two models. We will correct this in a future version.
  606. *
  607. * @param object model &$that
  608. * @return boolean
  609. * @throws PhpError
  610. * @access public
  611. */
  612. public function equals(&$that) {
  613. if (!is_a($that, 'Model')) {
  614. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: equals): Model expected.';
  615. trigger_error($errmsg, E_USER_ERROR);
  616. }
  617. if ($this->size() != $that->size())
  618. return FALSE;
  619. include_once(RDFAPI_INCLUDE_DIR . "util/ModelComparator.php");
  620. return ModelComparator::compare($this, $that);
  621. }
  622. /**
  623. * Return a new MemModel that is the set-union the model with another model.
  624. *
  625. * The result of taking the set-union of two or more RDF graphs (i.e. sets of triples)
  626. * is another graph, which we will call the merge of the graphs.
  627. * Each of the original graphs is a subgraph of the merged graph. Notice that when forming
  628. * a merged graph, two occurrences of a given uriref or literal as nodes in two different
  629. * graphs become a single node in the union graph (since by definition they are the same
  630. * uriref or literal) but blank nodes are not 'merged' in this way; and arcs are of course
  631. * never merged. In particular, this means that every blank node in a merged graph can be
  632. * identified as coming from one particular graph in the original set of graphs.
  633. *
  634. * Notice that one does not, in general, obtain the merge of a set of graphs by concatenating
  635. * their corresponding N-triples documents and constructing the graph described by the merged
  636. * document, since if some of the documents use the same node identifiers, the merged document
  637. * will describe a graph in which some of the blank nodes have been 'accidentally' merged.
  638. * To merge Ntriples documents it is necessary to check if the same nodeID is used in two or
  639. * more documents, and to replace it with a distinct nodeID in each of them, before merging the
  640. * documents. (Not implemented yet !!!!!!!!!!!)
  641. *
  642. * @param object Model $model
  643. * @return object MemModel
  644. * @throws PhpError
  645. * @access public
  646. *
  647. */
  648. public function unite(&$model) {
  649. if (!is_a($model, 'Model')) {
  650. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: unite): Model expected.';
  651. trigger_error($errmsg, E_USER_ERROR);
  652. }
  653. if (is_a($model, 'MemModel')) {
  654. $thisModel = & $this->getMemModel();
  655. return $thisModel->unite($model);
  656. } elseif (is_a($model, 'DbModel')) {
  657. $thisModel = & $this->getMemModel();
  658. $thatModel = & $model->getMemModel();
  659. return $thisModel->unite($thatModel);
  660. }
  661. }
  662. /**
  663. * Return a new MemModel that is the subtraction of another model from this DbModel.
  664. *
  665. * @param object Model $model
  666. * @return object MemModel
  667. * @throws PhpError
  668. * @access public
  669. */
  670. public function subtract(&$model) {
  671. if (!is_a($model, 'Model')) {
  672. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: subtract): Model expected.';
  673. trigger_error($errmsg, E_USER_ERROR);
  674. }
  675. if (is_a($model, 'MemModel')) {
  676. $thisModel = & $this->getMemModel();
  677. return $thisModel->subtract($model);
  678. } elseif (is_a($model, 'DbModel')) {
  679. $thisModel = & $this->getMemModel();
  680. $thatModel = & $model->getMemModel();
  681. return $thisModel->subtract($thatModel);
  682. }
  683. }
  684. /**
  685. * Return a new MemModel containing all the statements which are in both
  686. * this model and the given model.
  687. *
  688. * @param object Model $model
  689. * @return object MemModel
  690. * @throws PhpError
  691. * @access public
  692. */
  693. public function intersect(&$model) {
  694. if (is_a($model, 'MemModel')) {
  695. $thisModel = & $this->getMemModel();
  696. return $thisModel->intersect($model);
  697. } elseif (is_a($model, 'DbModel')) {
  698. $thisModel = & $this->getMemModel();
  699. $thatModel = & $model->getMemModel();
  700. return $thisModel->intersect($thatModel);
  701. }
  702. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: intersect: Model expected.';
  703. trigger_error($errmsg, E_USER_ERROR);
  704. }
  705. /**
  706. * Add the given model to this DbModel.
  707. * This public function monitors for SQL errors, and will commit if no errors have occured,
  708. * otherwise it will rollback.
  709. * If any statement of the model to be added to this model contains a blankNode
  710. * with an identifier already existing in this model, a new blankNode is generated.
  711. *
  712. * @param object Model $model
  713. * @throws PhpError
  714. * @access public
  715. */
  716. public function addModel(&$model) {
  717. if (!is_a($model, 'Model')) {
  718. $errmsg = RDFAPI_ERROR . '(class: DbModel; method: addModel): Model expected.';
  719. trigger_error($errmsg, E_USER_ERROR);
  720. }
  721. $blankNodes_tmp = array();
  722. if (is_a($model, 'MemModel')) {
  723. $this->dbConn->startTrans();
  724. foreach ($model->triples as $statement)
  725. $this->_addStatementFromAnotherModel($statement, $blankNodes_tmp);
  726. $this->addParsedNamespaces($model->getParsedNamespaces());
  727. $this->dbConn->completeTrans();
  728. } elseif (is_a($model, 'DbModel')) {
  729. $this->dbConn->startTrans();
  730. $memModel = & $model->getMemModel();
  731. foreach ($memModel->triples as $statement)
  732. $this->_addStatementFromAnotherModel($statement, $blankNodes_tmp);
  733. $this->addParsedNamespaces($model->getParsedNamespaces());
  734. $this->dbConn->completeTrans();
  735. }
  736. }
  737. /**
  738. * Reify the DbModel.
  739. * Return a new MemModel that contains the reifications of all statements of this DbModel.
  740. *
  741. * @return object MemModel
  742. * @access public
  743. */
  744. public function reify() {
  745. $memModel = & $this->getMemModel();
  746. return $memModel->reify();
  747. }
  748. /**
  749. * Remove this DbModel from database and clean up.
  750. * This public function monitors for SQL errors, and will commit if no errors have occured,
  751. * otherwise it will rollback.
  752. *
  753. * @throws SqlError
  754. * @access public
  755. */
  756. public function delete() {
  757. $this->dbConn->startTrans();
  758. $this->dbConn->execute('DELETE FROM models
  759. WHERE modelID=' . $this->modelID);
  760. $this->dbConn->execute('DELETE FROM statements
  761. WHERE modelID=' . $this->modelID);
  762. $this->dbConn->execute('DELETE FROM namespaces
  763. WHERE modelID=' . $this->modelID);
  764. if (!$this->dbConn->completeTrans())
  765. echo $this->dbConn->errorMsg();
  766. else
  767. $this->close();
  768. }
  769. /**
  770. * Close this DbModel
  771. *
  772. * @access public
  773. */
  774. public function close() {
  775. unset($this);
  776. }
  777. // =============================================================================
  778. // **************************** protected methods ********************************
  779. // =============================================================================
  780. /**
  781. * If the URI doesn't end with # : or /, then a # is added to the URI.
  782. * Used at setting the baseURI of this DbModel.
  783. *
  784. * @param string $uri
  785. * @return string
  786. * @access protected
  787. */
  788. protected function _checkBaseURI($uri) {
  789. if ($uri != NULL) {
  790. $c = substr($uri, strlen($uri) - 1, 1);
  791. if (!($c == '#' || $c == ':' || $c == '/' || $c == ""))
  792. $uri .= '#';
  793. }
  794. return $uri;
  795. }
  796. /* * '
  797. * Return the flag of the Node object.
  798. * r - Resource, b - BlankNode, l - Literal
  799. *
  800. * @param object Node $object
  801. * @return string
  802. * @access protected
  803. */
  804. protected function _getNodeFlag($object) {
  805. return is_a($object, 'BlankNode') ? 'b' : (is_a($object, 'Resource') ? 'r' : 'l');
  806. }
  807. /**
  808. * Convert an ADORecordSet to a memory Model.
  809. *
  810. * Every successful database query returns an ADORecordSet object which is actually
  811. * a cursor that holds the current row in the array fields[].
  812. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  813. * !!! This method can only be applied to a RecordSet with array fields[]
  814. * !!! containing a representation of the database table: statements,
  815. * !!! with an index corresponding to following table columns:
  816. * !!! [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  817. * !!! [4] - l_datatype, [5] - subject_is, [6] - object_is
  818. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  819. *
  820. * @param object ADORecordSet
  821. * @return object MemModel
  822. * @access protected
  823. */
  824. protected function _convertRecordSetToMemModel(&$recordSet) {
  825. $res = new MemModel($this->baseURI);
  826. while (!$recordSet->EOF) {
  827. // subject
  828. if ($recordSet->fields[5] == 'r')
  829. $sub = new Resource($recordSet->fields[0]);
  830. else
  831. $sub = new BlankNode($recordSet->fields[0]);
  832. // predicate
  833. $pred = new Resource($recordSet->fields[1]);
  834. // object
  835. if ($recordSet->fields[6] == 'r')
  836. $obj = new Resource($recordSet->fields[2]);
  837. elseif ($recordSet->fields[6] == 'b')
  838. $obj = new BlankNode($recordSet->fields[2]);
  839. else {
  840. $obj = new Literal($recordSet->fields[2], $recordSet->fields[3]);
  841. if ($recordSet->fields[4])
  842. $obj->setDatatype($recordSet->fields[4]);
  843. }
  844. $statement = new Statement($sub, $pred, $obj);
  845. $res->add($statement);
  846. $recordSet->moveNext();
  847. }
  848. $res->addParsedNamespaces($this->getParsedNamespaces());
  849. return $res;
  850. }
  851. /**
  852. * Create the dynamic part of an sql statement selecting triples with the
  853. * given parameters ($subject, $predicate, $object).
  854. *
  855. * @param object Resource $subject
  856. * @param object Resource $predicate
  857. * @param object Node $object
  858. * @return string
  859. * @access protected
  860. */
  861. protected function _createDynSqlPart_SPO($subject, $predicate, $object) {
  862. // conditions derived from the parameters passed to the function
  863. $subject_is = is_a($subject, 'BlankNode') ? 'b' : (is_a($subject, 'Resource') ? 'r' : 'l');
  864. $sql = '';
  865. if ($subject != NULL)
  866. $sql .= " AND subject='" . $subject->getLabel() . "'
  867. AND subject_is='" . $subject_is . "'";
  868. if ($predicate != NULL)
  869. $sql .= " AND predicate='" . $predicate->getLabel() . "'";
  870. if ($object != NULL) {
  871. $object_is = is_a($object, 'BlankNode') ? 'b' : (is_a($object, 'Resource') ? 'r' : 'l');
  872. if (is_a($object, 'Resource'))
  873. $sql .= " AND object='" . $object->getLabel() . "'
  874. AND object_is ='" . $object_is . "'";
  875. else {
  876. $quotedLiteral = $this->dbConn->qstr($object->getLabel());
  877. $sql .= " AND object=" . $quotedLiteral . "
  878. AND l_language='" . $object->getLanguage() . "'
  879. AND l_datatype='" . $object->getDataType() . "'
  880. AND object_is ='" . $object_is . "'";
  881. }
  882. }
  883. return $sql;
  884. }
  885. /**
  886. * Get an ADORecordSet with array fields[] containing a representation of
  887. * the given DbModel stored in the table: statements, with an index corresponding
  888. * to following table columns:
  889. * [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  890. * [4] - l_datatype, [5] - subject_is, [6] - object_is
  891. * (This method operates on data from a DbModel without loading it into a memory model
  892. * in order to save resources and improve speed).
  893. *
  894. * @param object DbModel $DbModel
  895. * @return object ADORecordSet
  896. * @access protected
  897. */
  898. protected function _getRecordSet(&$dbModel) {
  899. $sql = 'SELECT subject, predicate, object, l_language, l_datatype, subject_is, object_is
  900. FROM statements
  901. WHERE modelID = ' . $dbModel->modelID;
  902. return $recordSet = & $this->dbConn->execute($sql);
  903. }
  904. /**
  905. * Check if this DbModel contains the given row from the array fields[] of an ADORecordSet
  906. * The array index corresponds to following table columns:
  907. * [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  908. * [4] - l_datatype, [5] - subject_is, [6] - object_is
  909. *
  910. * @param array $row
  911. * @return boolean
  912. * @access protected
  913. */
  914. protected function _containsRow($row) {
  915. $sql = "SELECT modelID FROM statements
  916. WHERE modelID = " . $this->modelID . "
  917. AND subject =" . $this->dbConn->qstr($row[0]) . "
  918. AND predicate =" . $this->dbConn->qstr($row[1]) . "
  919. AND object =" . $this->dbConn->qstr($row[2]) . "
  920. AND l_language=" . $this->dbConn->qstr($row[3]) . "
  921. AND l_datatype=" . $this->dbConn->qstr($row[4]) . "
  922. AND subject_is=" . $this->dbConn->qstr($row[5]) . "
  923. AND object_is=" . $this->dbConn->qstr($row[6]);
  924. $res = & $this->dbConn->getOne($sql);
  925. if (!$res)
  926. return FALSE;
  927. return TRUE;
  928. }
  929. /**
  930. * Returns the models namespaces.
  931. *
  932. * @author Tobias Gauss <tobias.gauss@web.de>
  933. * @return mixed Array of key-value pairs. Namespace is the key,
  934. * prefix the value. If no namespaces are found,
  935. * boolean false is returned.
  936. *
  937. * @access public
  938. */
  939. public function getParsedNamespaces() {
  940. $sql = "SELECT * FROM namespaces
  941. WHERE modelID = " . $this->modelID;
  942. $temp = false;
  943. $res = $this->dbConn->execute($sql);
  944. if ($res) {
  945. while (!$res->EOF) {
  946. $temp[$res->fields[1]] = $res->fields[2];
  947. $res->moveNext();
  948. }
  949. }
  950. return $temp;
  951. }
  952. /**
  953. * Adds the namespaces to the model. This method is called by
  954. * the parser. !!!! addParsedNamespaces() not overwrites manual
  955. * added namespaces in the model !!!!
  956. *
  957. * @author Tobias Gauss <tobias.gauss@web.de>
  958. * @param array $newNs Array of namespace => prefix assignments
  959. *
  960. * @access public
  961. */
  962. public 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 Gauss <tobias.gauss@web.de>
  972. * @param string $prefix Prefix
  973. * @param string $nmsp Namespace URI
  974. *
  975. * @access public
  976. */
  977. public function addNamespace($prefix, $nmsp) {
  978. if ($nmsp != '' && $prefix != '') {
  979. if ($this->_checkNamespace($nmsp)) {
  980. $sql = "UPDATE namespaces SET prefix=" . $this->dbConn->qstr($prefix) . " WHERE
  981. modelID=" . $this->modelID . " AND namespace=" . $this->dbConn->qstr($nmsp);
  982. } else {
  983. $sql = "INSERT INTO namespaces
  984. (modelID, namespace, prefix)
  985. VALUES
  986. (" . $this->modelID . ','
  987. . $this->dbConn->qstr($nmsp) . ','
  988. . $this->dbConn->qstr($prefix) . ')';
  989. }
  990. $rs = & $this->dbConn->execute($sql);
  991. if (!$rs)
  992. $this->dbConn->errorMsg();
  993. }
  994. }
  995. /**
  996. * checks if a namespace is already in the model.
  997. *
  998. * @author Tobias Gauďż˝<tobias.gauss@web.de>
  999. * @access protected
  1000. * @param Array $newNs
  1001. */
  1002. protected function _checkNamespace($nmsp) {
  1003. $res = true;
  1004. $sql = "SELECT * FROM namespaces
  1005. WHERE modelID = " . $this->modelID . " AND
  1006. namespace=" . $this->dbConn->qstr($nmsp);
  1007. $rs = & $this->dbConn->execute($sql);
  1008. if (!$rs) {
  1009. $this->dbConn->errorMsg();
  1010. } else {
  1011. if ($rs->fields == false)
  1012. $res = false;
  1013. }
  1014. return $res;
  1015. }
  1016. /**
  1017. * Returns a FindIterator for traversing the MemModel.
  1018. * @access public
  1019. * @return object FindIterator
  1020. */
  1021. public function iterFind($sub = null, $pred = null, $obj = null) {
  1022. // Import Package Utility
  1023. include_once(RDFAPI_INCLUDE_DIR . PACKAGE_UTILITY);
  1024. $if = new IterFind($this, $sub, $pred, $obj);
  1025. return $if;
  1026. }
  1027. /**
  1028. * Removes a single namespace from the model
  1029. *
  1030. * @author Tobias Gauss <tobias.gauss@web.de>
  1031. * @param string $nmsp Namespace URI
  1032. *
  1033. * @return mixed True if all went well, error message otherwise
  1034. *
  1035. * @access public
  1036. */
  1037. public function removeNamespace($nmsp) {
  1038. $sql = 'DELETE FROM namespaces
  1039. WHERE modelID=' . $this->modelID . " AND namespace=" . $this->dbConn->qstr($nmsp);
  1040. $rs = & $this->dbConn->execute($sql);
  1041. if (!$rs)
  1042. return $this->dbConn->errorMsg();
  1043. else {
  1044. return true;
  1045. }
  1046. }
  1047. /**
  1048. * Add the given row from the array fields[] of an ADORecordSet to this DbModel
  1049. * The array index corresponds to following table columns:
  1050. * [0] - subject, [1] - predicate, [2] - object, [3] - l_language,
  1051. * [4] - l_datatype, [5] - subject_is, [6] - object_is
  1052. *
  1053. * @param array $row
  1054. * @throws SqlError
  1055. * @access protected
  1056. *
  1057. public function _insertRow ($row) {
  1058. $quotedObject = $this->dbConn->qstr($row[2]);
  1059. $sql = "INSERT INTO statements VALUES
  1060. (" .$this->modelID .","
  1061. ."'" .$row[0] ."',"
  1062. ."'" .$row[1] ."',"
  1063. ."" .$quotedObject .","
  1064. ."'" .$row[3] ."',"
  1065. ."'" .$row[4] ."',"
  1066. ."'" .$row[5] ."',"
  1067. ."'" .$row[6] ."')";
  1068. $rs =& $this->dbConn->execute($sql);
  1069. if (!$rs)
  1070. $this->dbConn->errorMsg();
  1071. }
  1072. */
  1073. }
  1074. // end: Class DbModel
  1075. ?>