source: Dev/branches/rest-dojo-ui/server/rdfapi/model/DbModel.php @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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