PageRenderTime 50ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/class/db/sql/MultiTableSQL.php

https://github.com/JeCat/framework
PHP | 275 lines | 183 code | 40 blank | 52 comment | 25 complexity | da421ab8771999d73f1798a0b8f42f6f MD5 | raw file
  1. <?php
  2. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3. // 这个文件是 JeCat PHP框架的一部分,该项目和此文件 均遵循 GNU 自由软件协议
  4. //
  5. // Copyleft 2008-2012 JeCat.cn(http://team.JeCat.cn)
  6. //
  7. //
  8. // JeCat PHP框架 的正式全名是:Jellicle Cat PHP Framework。
  9. // “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》(《Prologue:Jellicle Songs for Jellicle Cats》)。
  10. // JeCat 是一个开源项目,它像音乐剧中的猫一样自由,你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
  11. // 正在使用的这个版本是:0.7.1
  12. //
  13. //
  14. //
  15. // 相关的链接:
  16. // [主页] http://www.JeCat.cn
  17. // [源代码] https://github.com/JeCat/framework
  18. // [下载(http)] https://nodeload.github.com/JeCat/framework/zipball/master
  19. // [下载(git)] git clone git://github.com/JeCat/framework.git jecat
  20. // 不很相关:
  21. // [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
  22. // [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
  23. //
  24. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  25. /*-- Project Introduce --*/
  26. namespace org\jecat\framework\db\sql ;
  27. use org\jecat\framework\lang\Exception;
  28. abstract class MultiTableSQL extends SQL
  29. {
  30. function __construct($sTableName=null,$sTableAlias=null,$sForceIndex=null)
  31. {
  32. $this->arrRawSql = array(
  33. 'expr_type' => 'query' ,
  34. 'subtree' => array() ,
  35. ) ;
  36. if($sTableName)
  37. {
  38. $this->addTable($sTableName,$sTableAlias,$sForceIndex) ;
  39. }
  40. }
  41. function __clone()
  42. {}
  43. // -- from --
  44. /**
  45. * 参数 $table 可以是一个表示表名的字符串,也可以是一个 Table 对像
  46. *
  47. * @param $table string,Table
  48. */
  49. public function addTable($table,$sAlias=null,$sForceIndex=null)
  50. {
  51. if( is_string($table) )
  52. {
  53. $arrRawTable = self::createRawTable($table,$sAlias) ;
  54. }
  55. else if( $table instanceof Table )
  56. {
  57. $sAlias = $table->alias() ;
  58. $arrRawTable =& $table->rawSql() ;
  59. }
  60. else if( $table instanceof Select )
  61. {
  62. }
  63. // 未知类型
  64. else
  65. {
  66. throw new Exception("参数类型无效") ;
  67. }
  68. $arrRawFrom =& $this->rawClause($this->nTablesClause) ;
  69. if($sAlias)
  70. {
  71. $arrRawFrom['subtree'][$sAlias] =& $arrRawTable ;
  72. }
  73. else
  74. {
  75. $arrRawFrom['subtree'][] =& $arrRawTable ;
  76. }
  77. if($sForceIndex)
  78. {
  79. $arrRawTable['subtree'][] = "FORCE INDEX(`{$sForceIndex}`)" ;
  80. }
  81. }
  82. static private function tableFromRaw(array & $arrRawTable)
  83. {
  84. if(!isset($arrRawTable['object']))
  85. {
  86. switch ( $arrRawTable['expr_type'] )
  87. {
  88. case 'table':
  89. $arrRawTable['object'] = new Table() ;
  90. break ;
  91. case 'subquery':
  92. $arrRawTable['object'] = new Select() ;
  93. break ;
  94. default :
  95. throw new Exception("遇到无效的 table 类型: %s",$arrRawTable['expr_type']) ;
  96. break ;
  97. }
  98. $arrRawTable['object']->setRawSql($arrRawTable) ;
  99. }
  100. return $arrRawTable['object'] ;
  101. }
  102. /**
  103. * 返回指定数据表名所属的subtree数组,并加索引改为表名
  104. */
  105. protected function & findTableRaw($sTableName,array&$arrRawTree)
  106. {
  107. // 先用序号直接查找
  108. if( isset($this->arrRawSql['tables'][$sTableName]) )
  109. {
  110. return $this->arrRawSql['tables'][$sTableName] ;
  111. }
  112. foreach($arrRawTree as &$rawToken)
  113. {
  114. if( !is_array($rawToken) )
  115. {
  116. continue ;
  117. }
  118. else if( $rawToken['expr_type'] == 'table' )
  119. {
  120. if( $sTableName === (isset($rawToken['as'])? $rawToken['as']: $rawToken['table']) )
  121. {
  122. $this->arrRawSql['tables'][$sTableName] =& $rawToken ;
  123. return $rawToken ;
  124. }
  125. }
  126. // 递归
  127. if( !empty($rawToken['subtree']) )
  128. {
  129. if( $arrNameToken =& $this->findTableRaw($sTableName,$rawToken['subtree']) )
  130. {
  131. return $arrNameToken ;
  132. }
  133. }
  134. }
  135. return self::$null ;
  136. }
  137. public function joinTable($sFromTable,$sToTable,$sAlias=null,$on=null,$using=null,$sJoinType='LEFT')
  138. {
  139. $arrTokens = array() ;
  140. if($on)
  141. {
  142. array_push($arrTokens,'ON','(',$on,')') ;
  143. }
  144. if($using)
  145. {
  146. array_push($arrTokens,'USING','(',$using,')') ;
  147. }
  148. return $this->joinTableRaw($sFromTable,$sToTable,$sAlias,$sJoinType,$arrTokens) ;
  149. }
  150. public function joinTableRaw($sFromTable,$sToTable,$sAlias=null,$sJoinType='LEFT',array $arrRawTokens=array())
  151. {
  152. $arrRawFrom =& $this->rawClause($this->nTablesClause) ;
  153. if( !$arrFromTableToken=&$this->findTableRaw($sFromTable,$arrRawFrom['subtree']) )
  154. {
  155. throw new Exception("名为 %s 的数据表不存在,无法在该数据表上 join 另一个数据表(%s %s)。",array($sFromTable,$sToTable,$sAlias)) ;
  156. }
  157. array_unshift($arrRawTokens, $sJoinType,'JOIN','(',self::createRawTable($sToTable,$sAlias),')') ;
  158. $arrJoinToken = array(
  159. 'expr_type' => 'join_expression' ,
  160. 'type' => $sJoinType ,
  161. 'subtree' => &$arrRawTokens ,
  162. ) ;
  163. $arrFromTableToken['subtree'][] =& $arrJoinToken ;
  164. return $this ;
  165. }
  166. public function clearTables()
  167. {
  168. unset($this->arrRawSql[$this->nTablesClause]) ;
  169. }
  170. /**
  171. * @return array[Table]
  172. */
  173. public function tableIterator()
  174. {
  175. return isset($this->arrRawSql[$this->nTablesClause])?
  176. new \ArrayIterator(self::allTables($this->arrRawSql[$this->nTablesClause])) :
  177. new \EmptyIterator() ;
  178. }
  179. static private function allTables(&$arrTableList)
  180. {
  181. $arrTables = array() ;
  182. foreach($arrTableList as &$arrRawTable)
  183. {
  184. if( $arrRawTable['expr_type'] == 'table_expression' )
  185. {
  186. $arrTables = array_merge($arrTables,self::allTables($arrRawTable['subtree'])) ;
  187. }
  188. else
  189. {
  190. $arrTables[] = self::tableFromRaw($arrRawTable) ;
  191. }
  192. }
  193. return $arrTables ;
  194. }
  195. /**
  196. * @return array[Table]
  197. */
  198. public function table($sAlias)
  199. {
  200. if( !$arrTableList =& self::findTableList($sAlias,$this->rawClause($this->nTablesClause)) )
  201. {
  202. return null ;
  203. }
  204. return self::tableFromRaw($arrTableList[$sAlias]) ;
  205. }
  206. // ----------
  207. /**
  208. * @return Criteria
  209. */
  210. public function criteria($bAutoCreate=true)
  211. {
  212. if( !$this->aCriteria and $bAutoCreate )
  213. {
  214. $this->aCriteria = new Criteria($this->rawSql()) ;
  215. }
  216. return $this->aCriteria ;
  217. }
  218. /**
  219. * @return Criteria
  220. */
  221. public function setCriteria(Criteria $aCriteria)
  222. {
  223. $aCriteria->attache($this->rawSql()) ;
  224. }
  225. /**
  226. * @return Restriction
  227. */
  228. public function where($bAutoCreate=true)
  229. {
  230. return $this->criteria($bAutoCreate)->where($bAutoCreate) ;
  231. }
  232. private $aCriteria ;
  233. protected $nTablesClause = SQL::CLAUSE_FROM ;
  234. static private $null = null ;
  235. }