PageRenderTime 32ms CodeModel.GetById 16ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/Erfurt/Sparql/EngineDb/ResultRenderer/Plain.php

http://github.com/AKSW/Erfurt
PHP | 513 lines | 343 code | 62 blank | 108 comment | 61 complexity | 92b98396ca24481470da938304638ea2 MD5 | raw file
  1<?php
  2/**
  3 * This file is part of the {@link http://aksw.org/Projects/Erfurt Erfurt} project.
  4 *
  5 * @copyright Copyright (c) 2012, {@link http://aksw.org AKSW}
  6 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
  7 */
  8
  9require_once 'Erfurt/Sparql/EngineDb/ResultRenderer.php';
 10
 11/**
 12 * Result renderer that creates a text array
 13 *
 14 * This class was originally adopted from rdfapi-php (@link http://sourceforge.net/projects/rdfapi-php/).
 15 * It was modified and extended in order to fit into Erfurt.
 16 *
 17 * @package Erfurt_Sparql_EngineDb_ResultRenderer
 18 * @author Christian Weiske <cweiske@cweiske.de>
 19 * @author Philipp Frischmuth <pfrischmuth@googlemail.com>
 20 * @license http://www.gnu.org/licenses/lgpl.html LGPL
 21 */
 22class Erfurt_Sparql_EngineDb_ResultRenderer_Plain implements Erfurt_Sparql_EngineDb_ResultRenderer 
 23{
 24    // ------------------------------------------------------------------------
 25    // --- Protected properties -----------------------------------------------
 26    // ------------------------------------------------------------------------
 27        
 28    protected $uriValues = array();
 29    protected $literalValues = array();
 30    
 31    protected $_vars = null;
 32
 33    // ------------------------------------------------------------------------
 34    // --- Public methods -----------------------------------------------------
 35    // ------------------------------------------------------------------------
 36
 37    /**
 38     * Converts the database results into the desired output format
 39     * and returns the result.
 40     *
 41     * @param array $arRecordSets Array of (possibly several) SQL query results.
 42     * @param Erfurt_Sparql_Query $query SPARQL query object
 43     * @param $engine Sparql Engine to query the database
 44     * @return array
 45     */
 46    public function convertFromDbResults($arRecordSets, Erfurt_Sparql_Query $query, $engine, $vars)
 47    {
 48        $this->query    = $query;
 49        $this->engine   = $engine;
 50        $this->_vars    = $vars;
 51
 52        $strResultForm = $this->query->getResultForm();
 53        switch ($strResultForm) {
 54            case 'construct':
 55            case 'select':
 56            case 'select distinct':
 57                switch ($strResultForm) {
 58                    case 'construct':
 59                        $arResult = $this->_getVariableArrayFromRecordSets($arRecordSets, $strResultForm, true);
 60                        break;
 61                    default:
 62                        $arResult = $this->_getVariableArrayFromRecordSets($arRecordSets, $strResultForm, false);
 63                                              
 64                        if (count($this->uriValues) > 0 || count($this->literalValues) > 0) {
 65                            // If the query contains a ORDER BY wen need to reorder the result
 66                            $sm = $query->getSolutionModifier();
 67                            if (null !== $sm['order by']) {  
 68                                foreach ($sm['order by'] as $order) {
 69                                    $n = count($arResult);
 70                                    $id = ltrim($order['val'], '?$');
 71                                    while (true) {
 72                                        $hasChanged = false;
 73                                        
 74                                        for ($i=0; $i<$n-1; ++$i) {
 75                                            switch ($order['type']) {
 76                                                case 'desc':
 77                                                    if ($arResult[$i][$id] < $arResult[($i+1)][$id]) {
 78                                                        $dummy = $arResult[$i][$id];
 79                                                        $arResult[$i][$id] = $arResult[($i+1)][$id];
 80                                                        $arResult[($i+1)][$id] = $dummy;
 81
 82                                                        $hasChanged = true;
 83                                                    }
 84                                                    break;
 85                                                case 'asc':
 86                                                default:
 87                                                    if ($arResult[$i][$id] > $arResult[($i+1)][$id]) {
 88                                                        $dummy = $arResult[$i][$id];
 89                                                        $arResult[$i][$id] = $arResult[($i+1)][$id];
 90                                                        $arResult[($i+1)][$id] = $dummy;
 91
 92                                                        $hasChanged = true;
 93                                                    }
 94                                                    break;
 95                                                    
 96                                            } 
 97                                        }
 98                                        
 99                                        $n--;
100                                        
101                                        if (!$hasChanged && ($n === 0)) {
102                                            break;
103                                        }
104                                    }
105                                }
106                            }   
107                        }
108                }
109                
110                //some result forms need more modification
111                switch ($strResultForm) {
112                    case 'construct';
113                        $arResult = $this->_constructGraph(
114                            $arResult,
115                            $this->query->getConstructPattern()
116                        );
117                        break;
118                    case 'describe';
119                        $arResult = $this->describeGraph($arResult);
120                        break;
121                }
122
123                return $arResult;
124                break;
125            case 'count':
126            case 'count-distinct':
127            case 'ask':
128                if (count($arRecordSets) > 1) {
129                    require_once 'Erfurt/Exception.php';
130                    throw new Erfurt_Exception('More than one result set for a ' . $strResultForm . ' query!');
131                }
132
133                $nCount = 0;
134                foreach ($arRecordSets[0] as $row) {
135                    $nCount += intval($row['count']);
136                    break;
137                }
138
139                if ($strResultForm == 'ask') {
140                    return ($nCount > 0) ? true : false;
141                } else {
142                    return $nCount;
143                }
144                break;
145            case 'describe':
146            default:
147                throw new Exception('Yet not supported: ' . $strResultForm);
148        }
149
150    }
151
152    // ------------------------------------------------------------------------
153    // --- Protected methods --------------------------------------------------
154    // ------------------------------------------------------------------------
155
156    /**
157     * Constructs a result graph.
158     *
159     * @param  array $arVartable A table containing the result vars and their bindings.
160     * @param  Erfurt_Sparql_GraphPattern  $constructPattern The CONSTRUCT pattern.
161     * @return array
162     */
163    protected function _constructGraph($arVartable, $constructPattern)
164    {
165        $resultGraph = array();
166        
167        if (!$arVartable) {
168            return $resultGraph;
169        }
170
171        $tp = $constructPattern->getTriplePatterns();
172
173        $bnode = 0;
174        foreach ($arVartable as $value) {
175            foreach ($tp as $triple) {
176                $subVar  = substr($triple->getSubject(), 1);
177                $predVar = substr($triple->getPredicate(), 1);
178                $objVar  = substr($triple->getObject(), 1);
179                
180                $sub    = $value["$subVar"]['value'];
181                $pred   = $value["$predVar"]['value'];
182                $obj    = $value["$objVar"];
183                
184                if (!isset($resultGraph["$sub"])) {
185                    $resultGraph["$sub"] = array();
186                }
187                
188                if (!isset($resultGraph["$sub"]["$pred"])) {
189                    $resultGraph["$sub"]["$pred"] = array();
190                }
191                
192                $resultGraph["$sub"]["$pred"][] = $obj;
193            }  
194        }
195        
196        return $resultGraph;
197    }
198    
199    protected function _createBlankNode($id)
200    {
201        return array(
202            'type'  => 'bnode',
203            'value' => $id
204        );
205    }
206    
207    protected function _createLiteral($value, $language, $datatype)
208    {
209        
210        $retVal = array(
211            'type'  => 'literal',
212            'value' => $value
213        );
214                
215        if ((null !== $language)) {
216            $retVal['lang'] = $language;
217        } else if ((null !== $datatype)) {
218            $retVal['datatype'] = $datatype;
219        }
220        
221        return $retVal;
222    }
223    
224    /**
225     * Creates an RDF object object contained in the given $dbRecordSet object.
226     *
227     * @see convertFromDbResult() to understand $strVarBase necessity
228     *
229     * @param array $dbRecordSet
230     * @param string $strVarBase Prefix of the columns the recordset fields have.
231     * @return string RDF triple object resource object.
232     */
233    protected function _createObjectFromDbRecordSetPart($row, $strVarBase, $strVar, $asArray = false)
234    {
235        $strVarName = (string)$strVar;
236        
237        if ($row[$this->_vars[$strVarName]['sql_value']] === null) {
238            return '';
239        }
240        
241        $result = null;
242        switch ($row[$this->_vars[$strVarName]['sql_is']]) {
243            case 0:
244                if ($row[$this->_vars[$strVarName]['sql_ref']] === null) {
245                    $result = $this->_createResource($row[$this->_vars[$strVarName]['sql_value']]);
246                } else {
247                    $result =  $this->_createResource(
248                        $this->uriValues[$row[$this->_vars[$strVarName]['sql_ref']]]);
249                }
250                break;
251            case 1:
252                 if ($row[$this->_vars[$strVarName]['sql_ref']] === null) {
253                     $result = $this->_createBlankNode($row[$this->_vars[$strVarName]['sql_value']]);
254                } else {
255                    $result = $this->_createBlankNode(
256                        $this->uriValues[$row[$this->_vars[$strVarName]['sql_ref']]]);
257                }
258                break;
259            default:
260                 if ($row[$this->_vars[$strVarName]['sql_ref']] === null) {
261                     $result = $this->_createLiteral(
262                         $row[$this->_vars[$strVarName]['sql_value']], null, null);
263                    
264                    #if ($row[$this->_vars[$strVarName]['sql_dt_ref']] === null) {
265                    #    $result = $this->_createLiteral(
266                    #        $row[$this->_vars[$strVarName]['sql_value']],
267                    #        $row[$this->_vars[$strVarName]['sql_lang']],
268                    #        $row[$this->_vars[$strVarName]['sql_type']]
269                    #    );
270                    #} else {
271                    #    $result = $this->_createLiteral(
272                    #        $row[$this->_vars[$strVarName]['sql_value']],
273                    #        $row[$this->_vars[$strVarName]['sql_lang']],
274                    #        $this->uriValues[$row[$this->_vars[$strVarName]['sql_dt_ref']]]
275                    #    );
276                    #}
277                } else {
278                    $result = $this->_createLiteral(
279                         $this->literalValues[$row[$this->_vars[$strVarName]['sql_ref']]], null, null);
280                    
281                    #if ($row[$this->_vars[$strVarName]['sql_dt_ref']] === null) {
282                    #    $result = $this->_createLiteral(
283                    #        $this->literalValues[$row[$this->_vars[$strVarName]['sql_ref']]],
284                    #        $row[$this->_vars[$strVarName]['sql_lang']],
285                    #        $row[$this->_vars[$strVarName]['sql_type']]
286                    #    );
287                    #} else {
288                    #    $result = $this->_createLiteral(
289                    #        $this->literalValues[$row[$this->_vars[$strVarName]['sql_ref']]],
290                    #        $row[$this->_vars[$strVarName]['sql_lang']],
291                    #        $this->uriValues[$row[$this->_vars[$strVarName]['sql_dt_ref']]]
292                    #    );
293                    #}
294                }
295        }
296        
297        if ($asArray) {
298            return $result;
299        } else {
300            return $result['value'];
301        }
302    }
303
304    /**
305     * Creates an RDF predicate object contained in the given $dbRecordSet object.
306     *
307     * @see convertFromDbResult() to understand $strVarBase necessity
308     *
309     * @param array $dbRecordSet
310     * @param string $strVarBase Prefix of the columns the recordset fields have.
311     * @return string RDF triple predicate resource object.
312     */
313    protected function _createPredicateFromDbRecordSetPart($row, $strVarBase, $strVar, $asArray = false)
314    {
315        $strVarName = (string)$strVar;
316        
317        if ($row[$this->_vars[$strVarName]['sql_value']] === null) {
318            return '';
319        }
320        
321        $result = null;
322        if ($row[$this->_vars[$strVarName]['sql_ref']] === null) {
323            $result = $this->_createResource($row[$this->_vars[$strVarName]['sql_value']]);
324        } else {
325            $result = $this->_createResource($this->uriValues[$row[$this->_vars[$strVarName]['sql_ref']]]);
326        }
327    
328        if ($asArray) {
329            return $result;
330        } else {
331            return $result['value'];
332        }
333    }
334
335    protected function _createResource($uri)
336    {
337        return array(
338            'type'  => 'uri',
339            'value' => $uri
340        );
341    }
342    
343    /**
344     * Creates an RDF subject object contained in the given $dbRecordSet object.
345     *
346     * @see convertFromDbResult() to understand $strVarBase necessity
347     *
348     * @param array $dbRecordSet 
349     * @param string $strVarBase Prefix of the columns the recordset fields have.
350     * @return string RDF triple subject resource object.
351     */
352    protected function _createSubjectFromDbRecordSetPart($row, $strVarBase, $strVar, $asArray = false)
353    {
354        $strVarName = (string)$strVar;
355        
356        if ($row[$this->_vars[$strVarName]['sql_value']] === null) {
357            return '';
358        }
359
360        $result = null;
361        if ($row[$this->_vars[$strVarName]['sql_is']] === 0) {
362            if ($row[$this->_vars[$strVarName]['sql_ref']] === null) {
363                $result = $this->_createResource($row[$this->_vars[$strVarName]['sql_value']]);
364            } else {
365                $result = $this->_createResource($this->uriValues[$row[$this->_vars[$strVarName]['sql_ref']]]);
366            }
367        } else {
368            if ($row[$this->_vars[$strVarName]['sql_ref']] === null) {
369                $result = $this->_createBlankNode($row[$this->_vars[$strVarName]['sql_value']]);
370            } else {
371                $result = $this->_createBlankNode(
372                    $this->uriValues[$row[$this->_vars[$strVarName]['sql_ref']]]);
373            }
374        }
375        
376        if ($asArray) {
377            return $result;
378        } else {
379            return $result['value'];
380        }
381    }
382
383    /**
384     * Converts a result set array into an array of "rows" that
385     * are subarrays of variable => value pairs.
386     *
387     * @param $dbRecordSet
388     * @param $strResultForm
389     * @return array
390     */
391    protected function _getVariableArrayFromRecordSet($dbRecordSet, $strResultForm, $asArray = false)
392    {
393        $arResult = array();
394        switch ($strResultForm) {
395            case 'construct':
396                $arResultVars = $this->query->getConstructPatternVariables();
397                break;
398            default:
399                $arResultVars = $this->query->getResultVars();
400                break;
401        }
402
403        if (in_array('*', $arResultVars)) {
404            $arResultVars = array_keys($this->_vars);
405        }
406        
407        foreach ($dbRecordSet as $row) {
408            $arResultRow = array();
409            foreach ($arResultVars as $strVar) {
410                $strVarName = (string)$strVar;
411                $strVarId = ltrim($strVar, '?$');
412                if (!isset($this->_vars[$strVarName])) {
413                    //variable is in select, but not in result (test: q-select-2)
414                    $arResultRow[$strVarId] = '';
415                } else {
416                    $arVarSettings = $this->_vars[$strVarName];
417                    
418                    // Contains whether variable is s, p or o.
419                    switch ($arVarSettings[1]) {
420                        case 's':
421                            $arResultRow[$strVarId] = $this->_createSubjectFromDbRecordSetPart(
422                                $row, $arVarSettings[0], $strVar, $asArray);
423                            break;
424                        case 'p':
425                            $arResultRow[$strVarId] = $this->_createPredicateFromDbRecordSetPart(
426                                $row, $arVarSettings[0], $strVar, $asArray);
427                            break;
428                        case 'o':
429                            $arResultRow[$strVarId] = $this->_createObjectFromDbRecordSetPart(
430                                $row, $arVarSettings[0], $strVar, $asArray);
431                            break;
432                        default:
433                            require_once 'Erfurt/Exception.php';
434                            throw new Erfurt_Exception('Variable has to be s, p or o.');
435                    }
436                }
437            }
438            $arResult[] = $arResultRow;
439        }
440        return $arResult;
441    }
442    
443    protected function _getVariableArrayFromRecordSets($arRecordSets, $strResultForm, $asArray = false)
444    {
445        // First, we need to check, whether there is a need to dereference some values
446        $refVariableNamesUri = array();
447        $refVariableNamesLit = array();
448        foreach ($this->_vars as $var) {
449            if ($var[1] === 'o') {
450                if (isset($var['sql_ref'])) {
451                    $refVariableNamesLit[] = $var['sql_ref'];
452                    $refVariableNamesUri[] = $var['sql_ref'];
453                }
454                if (isset($var['sql_dt_ref'])) {
455                    $refVariableNamesUri[] = $var['sql_dt_ref'];
456                }
457            } else {
458                if (isset($var['sql_ref'])) {
459                    $refVariableNamesUri[] = $var['sql_ref'];
460                }
461            }   
462        }
463;
464        $refVariableNamesUri = array_unique($refVariableNamesUri);
465        $refVariableNamesLit = array_unique($refVariableNamesLit);
466
467        $refIdsUri = array();
468        $refIdsLit = array();
469        foreach ($arRecordSets as $dbRecordSet) {
470            foreach ($dbRecordSet as $row) {
471                foreach ($refVariableNamesUri as $name) {
472                    if ($row["$name"] !== null) {
473                        $refIdsUri[] = $row["$name"];
474                    }
475                }
476                foreach ($refVariableNamesLit as $name) {
477                    if ($row["$name"] !== null) {
478                        $refIdsLit[] = $row["$name"];
479                    }
480                }
481            }
482        }
483 
484        if (count($refIdsUri) > 0) {
485            $sql = 'SELECT id, v FROM ef_uri WHERE id IN (' . implode(',', $refIdsUri) . ')';
486            
487            $result = $this->engine->sqlQuery($sql);
488          
489            foreach ($result as $row) {
490                $this->uriValues[$row['id']] = $row['v'];
491            }
492            
493        }
494   
495        if (count($refIdsLit) > 0) {
496            $sql = 'SELECT id, v FROM ef_lit WHERE id IN (' . implode(',', $refIdsLit) . ')';
497            
498            $result = $this->engine->sqlQuery($sql);
499            foreach ($result as $row) {
500                $this->literalValues[$row['id']] = $row['v'];
501            }
502        }
503        
504        $arResult = array();
505        foreach ($arRecordSets as $dbRecordSet) {
506            $arResult = array_merge(
507                $arResult,
508                $this->_getVariableArrayFromRecordSet($dbRecordSet, $strResultForm, $asArray)
509            );
510        }
511        return $arResult;
512    }
513}