PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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