PageRenderTime 29ms CodeModel.GetById 15ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/Erfurt/Sparql/EngineDb/Adapter/EfZendDb.php

http://github.com/AKSW/Erfurt
PHP | 388 lines | 136 code | 47 blank | 205 comment | 19 complexity | 3b7f2b189fe50ea811c6428039c042a7 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
  9/**
 10 * SPARQL engine optimized for databases.
 11 * Generates SQL statements to directly query the database,
 12 * letting the database system do all the hard work like
 13 * selecting, joining, filtering and ordering results.
 14 *
 15 * This class was originally adopted from rdfapi-php (@link http://sourceforge.net/projects/rdfapi-php/).
 16 * It was modified and extended in order to fit into Erfurt.
 17 *
 18 * @package Erfurt_Sparql_EngineDb_Adapter
 19 * @author Christian Weiske <cweiske@cweiske.de>
 20 * @author Philipp Frischmuth <pfrischmuth@googlemail.com>
 21 * @license http://www.gnu.org/licenses/lgpl.html LGPL
 22 */
 23class Erfurt_Sparql_EngineDb_Adapter_EfZendDb 
 24{   
 25	/**
 26     * Sparql Query object.
 27     *
 28     * @var Erfurt_Sparql_Query
 29     */
 30    protected $query;
 31
 32    /**
 33     * RDF dataset object.
 34     *
 35     * @var Dataset
 36     */
 37    //protected $dataset;
 38
 39    /**
 40     *   Database connection object.
 41     *   @var object zenddb connection
 42     */
 43    protected $dbConn;
 44
 45    /**
 46    *   Internal ID for our graph model.
 47    *   Stored in the database along the statements.
 48    *   Can be of different types:
 49    *   - array: array of modelIds
 50    *   - null: all models
 51    *
 52    *   @var array OR null
 53    */
 54    protected $arModelIds;
 55
 56    /**
 57    *   Prepared SQL statements are stored in here.
 58    *   @var array
 59    */
 60    protected $arPrepared    = null;
 61
 62    /**
 63    *   If the prepared statement is really prepared, or if we just emulate it.
 64    *   @var boolean
 65    */
 66    protected $bRealPrepared = false;
 67
 68    /**
 69    *   SQL generator instance
 70    *   @var SparqlEngineDb_SqlGenerator
 71    */
 72    protected $sg = null;
 73
 74    /**
 75    *   Type sorting instance
 76    *   @var SparqlEngineDb_TypeSorter
 77    */
 78    protected $ts = null;
 79
 80    /**
 81    *   Prepared statments preparator instance
 82    *   @var SparqlEngineDb_Preparator
 83    */
 84    protected $pr = null;
 85    
 86    protected $arModelIdMapping = null;
 87
 88    // ------------------------------------------------------------------------
 89    // --- Magic methods ------------------------------------------------------
 90    // ------------------------------------------------------------------------
 91
 92    /**
 93     * Constructor
 94     */
 95    public function __construct($dbConn, $arModelIdMapping = array()) 
 96    {
 97		$this->dbConn = $dbConn;
 98		$this->arModelIdMapping = $arModelIdMapping;
 99    }
100    
101    public function getModelIdMapping()
102    {
103        return $this->arModelIdMapping;
104    }
105    
106    // ------------------------------------------------------------------------
107    // --- Public methods -----------------------------------------------------
108    // ------------------------------------------------------------------------
109
110    public function getQuery()
111    {
112        return $this->query;
113    }
114
115    public function getSqlGenerator()
116    {
117        return $this->sg;
118    }
119    
120    public function getTypeSorter()
121    {
122        return $this->ts;
123    }
124
125    /**
126     *   Create a prepared statement that can be executed later.
127     *
128     *   @param  Dataset       $dataset    RDF Dataset
129     *   @param  Query         $query      Parsed SPARQL query
130     *
131     *   @return SparqlEngineDb_PreparedStatement Prepared statment that can
132     *           be execute()d later.
133     */
134    /*public function prepare(Dataset $dataset, Query $query)
135    {
136        //require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/PreparedStatement.php';
137        //require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/Preparator.php';
138
139        $this->query   = $query;
140        $this->dataset = $dataset;
141        $this->sg = new SparqlEngineDb_SqlGenerator   ($this->query, $this->dbConn, $this->arModelIds);
142        $this->rc = new SparqlEngineDb_ResultConverter($this->query, $this->sg, $this);
143        $this->ts = new SparqlEngineDb_TypeSorter     ($this->query, $this->dbConn);
144        $this->pr = new SparqlEngineDb_Preparator     ($this->query, $this->dbConn);
145
146        $this->arPrepared = $this->sg->createSql();
147        $this->ts->setData($this->sg);
148
149        if ($this->ts->willBeDataDependent()) {
150            $this->bRealPrepared = false;
151        } else {
152            $this->bRealPrepared     = true;
153            list($strSelect, $strFrom, $strWhere) = $this->arPrepared;
154            $this->arPreparedQueries = $this->ts->getOrderifiedSqls(
155                $strSelect,
156                $strFrom,
157                $strWhere
158            );
159            $this->arDbStatements    = $this->pr->prepareInDb(
160                $this->arPreparedQueries,
161                $this->sg->getPlaceholders()
162            );
163        }
164
165
166        return new SparqlEngineDb_PreparedStatement(
167            $this
168        );
169    }*/
170    
171    /**
172     *   Execute a prepared statement by filling it with variables
173     *
174     *   @param array $arVariables   Array with (variable name => value) pairs
175     *   @param string $resultform   Which form the result should have
176     *
177     *   @return mixed   Result according to $resultform
178     */
179    /*public function execute($arVariables, $resultform = false)
180    {
181        if ($this->arPrepared === null) {
182            throw new Exception('You need to prepare() the query first.');
183        }
184
185        if ($this->bRealPrepared) {
186            return
187                SparqlEngineDb_ResultConverter::convertFromDbResults(
188                    $this->pr->execute(
189                        $this->arDbStatements,
190                        $arVariables
191                    ),
192                    $this,
193                    $resultform
194                );
195        } else {
196            list($strSelect, $strFrom, $strWhere) = $this->arPrepared;
197
198            return SparqlEngineDb_ResultConverter::convertFromDbResults(
199                $this->_queryMultiple(
200                    $this->ts->getOrderifiedSqls(
201                        $strSelect,
202                        $strFrom,
203                        $this->pr->replacePlaceholdersWithVariables(
204                            $strWhere,
205                            $this->sg->getPlaceholders(),
206                            $arVariables
207                        )
208                    )
209                ),
210                $this,
211                $resultform
212            );
213        }
214    }*/
215
216    /**
217     * Query the database with the given SPARQL query.
218     *
219     * @param Erfurt_SparqlQuery $query Parsed SPARQL query.
220     * @param string $resultform Result form. If set to 'xml' the result will be
221     * SPARQL Query Results XML Format as described in @link http://www.w3.org/TR/rdf-sparql-XMLres/.
222     *
223     * @return array/string  array of triple arrays, or XML. 
224     * Format depends on $resultform parameter.
225     */
226    public function queryModel(Erfurt_Sparql_Query $query, $resultform = 'plain') 
227    {   
228        $this->query = $query;
229
230        require_once 'Erfurt/Sparql/EngineDb/QuerySimplifier.php';
231        $qsimp = new Erfurt_Sparql_EngineDb_QuerySimplifier();
232        $qsimp->simplify($this->query);
233
234        require_once 'Erfurt/Sparql/EngineDb/QueryOptimizer.php';
235        $queryOptimizer = new Erfurt_Sparql_EngineDb_QueryOptimizer($this);
236        $result = $queryOptimizer->optimize($this->query);
237 		
238        
239        if ($result instanceof Erfurt_Sparql_Query) {
240            $this->query = $result;
241        } 
242        
243        $resultform = strtolower($resultform);
244        switch ($resultform) {
245            case 'xml':
246                require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Xml.php';
247                $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Xml();
248                break;
249                //require_once 'Erfurt/Exception.php';
250                //throw new Erfurt_Exception('XML result format not supported yet.');
251                //require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/EfZendDb/Xml.php';
252                //$this->rc = new Erfurt_Sparql_EngineDb_ResultRenderer_RapZendDb_Xml();
253                //break;
254            case 'extended':
255                require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Extended.php';
256                $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Extended();
257                break;
258            case 'json':
259                require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Json.php';
260                $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Json();
261                break;
262            case 'plain':
263            default:
264                require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Plain.php';
265                $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Plain();
266        }
267        
268        if (is_array($result)) {
269            $result = $rc->convertFromDbResults($result['data'], $this->query, $this, $result['vars']);
270            
271            return $result;
272        }
273        
274               
275        require_once 'Erfurt/Sparql/EngineDb/SqlGenerator/Adapter/Ef.php';
276        $this->sg = new Erfurt_Sparql_EngineDb_SqlGenerator_Adapter_Ef($this->query, $this->arModelIdMapping);
277        
278        require_once 'Erfurt/Sparql/EngineDb/TypeSorter.php';
279        $this->ts = new Erfurt_Sparql_EngineDb_TypeSorter($this->query, $this);
280
281        $this->_setOptions();
282
283        $arSqls = $this->sg->createSql();
284        #var_dump($arSqls);exit;
285        
286        $this->ts->setData($this->sg);
287        
288        return $rc->convertFromDbResults($this->_queryMultiple($this->ts->getOrderifiedSqls($arSqls)),
289                    $this->query, $this, $this->sg->arVarAssignments);
290    }
291    
292    public function sqlQuery($sql)
293    {
294        return $this->dbConn->fetchAll($sql);
295    }
296
297    // ------------------------------------------------------------------------
298    // --- Protected methods --------------------------------------------------
299    // ------------------------------------------------------------------------
300
301    /**
302     * Sends the sql to the database and returns the results.
303     *
304     * @param array $arSql Array that gets a SQL query string once imploded.
305     *
306     * @return mixed
307     */
308    protected function _queryDb($arSql, $nOffset, $nLimit)
309    {
310        require_once 'Erfurt/Sparql/EngineDb/SqlMerger.php';
311        $strSql = Erfurt_Sparql_EngineDb_SqlMerger::getSelect($this->query, $arSql);
312#var_dump($nLimit, $nOffset);
313#echo $strSql;
314        if ($strSql === '()') {
315            return array();
316        }
317      
318        if ($nLimit === null && $nOffset == 0) {
319            $ret = @$this->dbConn->query($strSql);
320        } else if ($nLimit === null) {
321            $ret = @$this->dbConn->query($strSql . ' LIMIT ' . $nOffset . ', 18446744073709551615');
322        } else {
323            $ret = @$this->dbConn->query($strSql . ' LIMIT ' . $nOffset . ', ' . $nLimit);
324        }
325
326        return $ret->fetchAll();
327    }
328
329    /**
330     * Executes multiple SQL queries and returns an array of results.
331     *
332     * @param array $arSqls Array of SQL queries.
333     * @return array Array of query results.
334     */
335    protected function _queryMultiple($arSqls)
336    {
337        $arSM = $this->query->getSolutionModifier();
338        
339        if ($arSM['limit'] === null && $arSM['offset'] === null) {
340            $nOffset = 0;
341            $nLimit  = null;
342            $nSql    = 0;
343        } else {
344            require_once 'Erfurt/Sparql/EngineDb/Offsetter.php';
345            $offsetter = new Erfurt_Sparql_EngineDb_Offsetter($this, $this->query);
346            list($nSql, $nOffset) = $offsetter->determineOffset($arSqls);
347            $nLimit    = $arSM['limit'];
348        }
349
350        $nCount    = 0;
351        $arResults = array();
352        foreach ($arSqls as $nId => $arSql) {
353            if ($nId < $nSql) { 
354                continue; 
355            }
356
357            if ($nLimit != null) {
358                $nCurrentLimit = $nLimit - $nCount;
359            } else {
360                $nCurrentLimit = null;
361            }
362
363            $dbResult = $this->_queryDb($arSql, $nOffset, $nCurrentLimit);
364            
365            $nCount     += count($dbResult);
366            $arResults[] = $dbResult;
367            $nOffset = 0;
368            if ($nLimit !== null && $nCount >= $nLimit) {
369                break;
370            }
371        }
372        
373        return $arResults;
374    }
375
376    /**
377     * Set options to subobjects like SqlGenerator
378     */
379    protected function _setOptions()
380    {
381        // allow changing the statements' table name
382        //if (isset($GLOBALS['RAP']['conf']['database']['tblStatements'])) {
383        //    $this->sg->setStatementsTable(
384        //        $GLOBALS['RAP']['conf']['database']['tblStatements']
385        //    );
386        //}
387    }
388}