PageRenderTime 35ms CodeModel.GetById 19ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 1ms

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

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