mapper.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. <?php
  2. /*
  3. Copyright (c) 2009-2017 F3::Factory/Bong Cosca, All rights reserved.
  4. This file is part of the Fat-Free Framework (http://fatfreeframework.com).
  5. This is free software: you can redistribute it and/or modify it under the
  6. terms of the GNU General Public License as published by the Free Software
  7. Foundation, either version 3 of the License, or later.
  8. Fat-Free Framework is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with Fat-Free Framework. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. namespace DB\SQL;
  16. //! SQL data mapper
  17. class Mapper extends \DB\Cursor {
  18. protected
  19. //! PDO wrapper
  20. $db,
  21. //! Database engine
  22. $engine,
  23. //! SQL table
  24. $source,
  25. //! SQL table (quoted)
  26. $table,
  27. //! Alias for SQL table
  28. $as,
  29. //! Last insert ID
  30. $_id,
  31. //! Defined fields
  32. $fields,
  33. //! Adhoc fields
  34. $adhoc=[],
  35. //! Dynamic properties
  36. $props=[];
  37. /**
  38. * Return database type
  39. * @return string
  40. **/
  41. function dbtype() {
  42. return 'SQL';
  43. }
  44. /**
  45. * Return mapped table
  46. * @return string
  47. **/
  48. function table() {
  49. return $this->source;
  50. }
  51. /**
  52. * Return TRUE if any/specified field value has changed
  53. * @return bool
  54. * @param $key string
  55. **/
  56. function changed($key=NULL) {
  57. if (isset($key))
  58. return $this->fields[$key]['changed'];
  59. foreach($this->fields as $key=>$field)
  60. if ($field['changed'])
  61. return TRUE;
  62. return FALSE;
  63. }
  64. /**
  65. * Return TRUE if field is defined
  66. * @return bool
  67. * @param $key string
  68. **/
  69. function exists($key) {
  70. return array_key_exists($key,$this->fields+$this->adhoc);
  71. }
  72. /**
  73. * Assign value to field
  74. * @return scalar
  75. * @param $key string
  76. * @param $val scalar
  77. **/
  78. function set($key,$val) {
  79. if (array_key_exists($key,$this->fields)) {
  80. $val=is_null($val) && $this->fields[$key]['nullable']?
  81. NULL:$this->db->value($this->fields[$key]['pdo_type'],$val);
  82. if ($this->fields[$key]['initial']!==$val ||
  83. $this->fields[$key]['default']!==$val && is_null($val))
  84. $this->fields[$key]['changed']=TRUE;
  85. return $this->fields[$key]['value']=$val;
  86. }
  87. // Adjust result on existing expressions
  88. if (isset($this->adhoc[$key]))
  89. $this->adhoc[$key]['value']=$val;
  90. elseif (is_string($val))
  91. // Parenthesize expression in case it's a subquery
  92. $this->adhoc[$key]=['expr'=>'('.$val.')','value'=>NULL];
  93. else
  94. $this->props[$key]=$val;
  95. return $val;
  96. }
  97. /**
  98. * Retrieve value of field
  99. * @return scalar
  100. * @param $key string
  101. **/
  102. function &get($key) {
  103. if ($key=='_id')
  104. return $this->_id;
  105. elseif (array_key_exists($key,$this->fields))
  106. return $this->fields[$key]['value'];
  107. elseif (array_key_exists($key,$this->adhoc))
  108. return $this->adhoc[$key]['value'];
  109. elseif (array_key_exists($key,$this->props))
  110. return $this->props[$key];
  111. user_error(sprintf(self::E_Field,$key),E_USER_ERROR);
  112. }
  113. /**
  114. * Clear value of field
  115. * @return NULL
  116. * @param $key string
  117. **/
  118. function clear($key) {
  119. if (array_key_exists($key,$this->adhoc))
  120. unset($this->adhoc[$key]);
  121. else
  122. unset($this->props[$key]);
  123. }
  124. /**
  125. * Invoke dynamic method
  126. * @return mixed
  127. * @param $func string
  128. * @param $args array
  129. **/
  130. function __call($func,$args) {
  131. return call_user_func_array(
  132. (array_key_exists($func,$this->props)?
  133. $this->props[$func]:
  134. $this->$func),$args
  135. );
  136. }
  137. /**
  138. * Convert array to mapper object
  139. * @return static
  140. * @param $row array
  141. **/
  142. function factory($row) {
  143. $mapper=clone($this);
  144. $mapper->reset();
  145. foreach ($row as $key=>$val) {
  146. if (array_key_exists($key,$this->fields))
  147. $var='fields';
  148. elseif (array_key_exists($key,$this->adhoc))
  149. $var='adhoc';
  150. else
  151. continue;
  152. $mapper->{$var}[$key]['value']=$val;
  153. $mapper->{$var}[$key]['initial']=$val;
  154. if ($var=='fields' && $mapper->{$var}[$key]['pkey'])
  155. $mapper->{$var}[$key]['previous']=$val;
  156. }
  157. $mapper->query=[clone($mapper)];
  158. if (isset($mapper->trigger['load']))
  159. \Base::instance()->call($mapper->trigger['load'],$mapper);
  160. return $mapper;
  161. }
  162. /**
  163. * Return fields of mapper object as an associative array
  164. * @return array
  165. * @param $obj object
  166. **/
  167. function cast($obj=NULL) {
  168. if (!$obj)
  169. $obj=$this;
  170. return array_map(
  171. function($row) {
  172. return $row['value'];
  173. },
  174. $obj->fields+$obj->adhoc
  175. );
  176. }
  177. /**
  178. * Build query string and arguments
  179. * @return array
  180. * @param $fields string
  181. * @param $filter string|array
  182. * @param $options array
  183. **/
  184. function stringify($fields,$filter=NULL,array $options=NULL) {
  185. if (!$options)
  186. $options=[];
  187. $options+=[
  188. 'group'=>NULL,
  189. 'order'=>NULL,
  190. 'limit'=>0,
  191. 'offset'=>0,
  192. 'comment'=>NULL
  193. ];
  194. $db=$this->db;
  195. $sql='SELECT '.$fields.' FROM '.$this->table;
  196. if (isset($this->as))
  197. $sql.=' AS '.$this->db->quotekey($this->as);
  198. $args=[];
  199. if (is_array($filter)) {
  200. $args=isset($filter[1]) && is_array($filter[1])?
  201. $filter[1]:
  202. array_slice($filter,1,NULL,TRUE);
  203. $args=is_array($args)?$args:[1=>$args];
  204. list($filter)=$filter;
  205. }
  206. if ($filter)
  207. $sql.=' WHERE '.$filter;
  208. if ($options['group']) {
  209. $sql.=' GROUP BY '.implode(',',array_map(
  210. function($str) use($db) {
  211. return preg_replace_callback(
  212. '/\b(\w+[._\-\w]*)\h*(HAVING.+|$)/i',
  213. function($parts) use($db) {
  214. return $db->quotekey($parts[1]).
  215. (isset($parts[2])?(' '.$parts[2]):'');
  216. },
  217. $str
  218. );
  219. },
  220. explode(',',$options['group'])));
  221. }
  222. if ($options['order']) {
  223. $char=substr($db->quotekey(''),0,1);// quoting char
  224. $order=' ORDER BY '.(is_bool(strpos($options['order'],$char))?
  225. implode(',',array_map(function($str) use($db) {
  226. return preg_match('/^\h*(\w+[._\-\w]*)'.
  227. '(?:\h+((?:ASC|DESC)[\w\h]*))?\h*$/i',
  228. $str,$parts)?
  229. ($db->quotekey($parts[1]).
  230. (isset($parts[2])?(' '.$parts[2]):'')):$str;
  231. },explode(',',$options['order']))):
  232. $options['order']);
  233. }
  234. // SQL Server fixes
  235. if (preg_match('/mssql|sqlsrv|odbc/', $this->engine) &&
  236. ($options['limit'] || $options['offset'])) {
  237. // order by pkey when no ordering option was given
  238. if (!$options['order'])
  239. foreach ($this->fields as $key=>$field)
  240. if ($field['pkey']) {
  241. $order=' ORDER BY '.$db->quotekey($key);
  242. break;
  243. }
  244. $ofs=$options['offset']?(int)$options['offset']:0;
  245. $lmt=$options['limit']?(int)$options['limit']:0;
  246. if (strncmp($db->version(),'11',2)>=0) {
  247. // SQL Server >= 2012
  248. $sql.=$order.' OFFSET '.$ofs.' ROWS';
  249. if ($lmt)
  250. $sql.=' FETCH NEXT '.$lmt.' ROWS ONLY';
  251. }
  252. else {
  253. // SQL Server 2008
  254. $sql=preg_replace('/SELECT/',
  255. 'SELECT '.
  256. ($lmt>0?'TOP '.($ofs+$lmt):'').' ROW_NUMBER() '.
  257. 'OVER ('.$order.') AS rnum,',$sql.$order,1);
  258. $sql='SELECT * FROM ('.$sql.') x WHERE rnum > '.($ofs);
  259. }
  260. }
  261. else {
  262. if (isset($order))
  263. $sql.=$order;
  264. if ($options['limit'])
  265. $sql.=' LIMIT '.(int)$options['limit'];
  266. if ($options['offset'])
  267. $sql.=' OFFSET '.(int)$options['offset'];
  268. }
  269. if ($options['comment'])
  270. $sql.="\n".' /* '.$options['comment'].' */';
  271. return [$sql,$args];
  272. }
  273. /**
  274. * Build query string and execute
  275. * @return static[]
  276. * @param $fields string
  277. * @param $filter string|array
  278. * @param $options array
  279. * @param $ttl int|array
  280. **/
  281. function select($fields,$filter=NULL,array $options=NULL,$ttl=0) {
  282. list($sql,$args)=$this->stringify($fields,$filter,$options);
  283. $result=$this->db->exec($sql,$args,$ttl);
  284. $out=[];
  285. foreach ($result as &$row) {
  286. foreach ($row as $field=>&$val) {
  287. if (array_key_exists($field,$this->fields)) {
  288. if (!is_null($val) || !$this->fields[$field]['nullable'])
  289. $val=$this->db->value(
  290. $this->fields[$field]['pdo_type'],$val);
  291. }
  292. unset($val);
  293. }
  294. $out[]=$this->factory($row);
  295. unset($row);
  296. }
  297. return $out;
  298. }
  299. /**
  300. * Return records that match criteria
  301. * @return static[]
  302. * @param $filter string|array
  303. * @param $options array
  304. * @param $ttl int|array
  305. **/
  306. function find($filter=NULL,array $options=NULL,$ttl=0) {
  307. if (!$options)
  308. $options=[];
  309. $options+=[
  310. 'group'=>NULL,
  311. 'order'=>NULL,
  312. 'limit'=>0,
  313. 'offset'=>0
  314. ];
  315. $adhoc='';
  316. foreach ($this->adhoc as $key=>$field)
  317. $adhoc.=','.$field['expr'].' AS '.$this->db->quotekey($key);
  318. return $this->select(
  319. ($options['group'] && !preg_match('/mysql|sqlite/',$this->engine)?
  320. $options['group']:
  321. implode(',',array_map([$this->db,'quotekey'],
  322. array_keys($this->fields)))).$adhoc,$filter,$options,$ttl);
  323. }
  324. /**
  325. * Count records that match criteria
  326. * @return int
  327. * @param $filter string|array
  328. * @param $options array
  329. * @param $ttl int|array
  330. **/
  331. function count($filter=NULL,array $options=NULL,$ttl=0) {
  332. if (!($subquery_mode=($options && !empty($options['group']))))
  333. $this->adhoc['_rows']=['expr'=>'COUNT(*)','value'=>NULL];
  334. $adhoc=[];
  335. foreach ($this->adhoc as $key=>$field)
  336. // Add all adhoc fields
  337. // (make them available for grouping, sorting, having)
  338. $adhoc[]=$field['expr'].' AS '.$this->db->quotekey($key);
  339. $fields=implode(',',$adhoc);
  340. if ($subquery_mode) {
  341. if (empty($fields))
  342. // Select at least one field, ideally the grouping fields
  343. // or sqlsrv fails
  344. $fields=preg_replace('/HAVING.+$/i','',$options['group']);
  345. if (preg_match('/mssql|dblib|sqlsrv/',$this->engine))
  346. $fields='TOP 100 PERCENT '.$fields;
  347. }
  348. list($sql,$args)=$this->stringify($fields,$filter,$options);
  349. if ($subquery_mode)
  350. $sql='SELECT COUNT(*) AS '.$this->db->quotekey('_rows').' '.
  351. 'FROM ('.$sql.') AS '.$this->db->quotekey('_temp');
  352. $result=$this->db->exec($sql,$args,$ttl);
  353. unset($this->adhoc['_rows']);
  354. return (int)$result[0]['_rows'];
  355. }
  356. /**
  357. * Return record at specified offset using same criteria as
  358. * previous load() call and make it active
  359. * @return static
  360. * @param $ofs int
  361. **/
  362. function skip($ofs=1) {
  363. $out=parent::skip($ofs);
  364. $dry=$this->dry();
  365. foreach ($this->fields as $key=>&$field) {
  366. $field['value']=$dry?NULL:$out->fields[$key]['value'];
  367. $field['initial']=$field['value'];
  368. $field['changed']=FALSE;
  369. if ($field['pkey'])
  370. $field['previous']=$dry?NULL:$out->fields[$key]['value'];
  371. unset($field);
  372. }
  373. foreach ($this->adhoc as $key=>&$field) {
  374. $field['value']=$dry?NULL:$out->adhoc[$key]['value'];
  375. unset($field);
  376. }
  377. if (!$dry && isset($this->trigger['load']))
  378. \Base::instance()->call($this->trigger['load'],$this);
  379. return $out;
  380. }
  381. /**
  382. * Insert new record
  383. * @return static
  384. **/
  385. function insert() {
  386. $args=[];
  387. $actr=0;
  388. $nctr=0;
  389. $fields='';
  390. $values='';
  391. $filter='';
  392. $pkeys=[];
  393. $nkeys=[];
  394. $ckeys=[];
  395. $inc=NULL;
  396. foreach ($this->fields as $key=>$field)
  397. if ($field['pkey'])
  398. $pkeys[$key]=$field['previous'];
  399. if (isset($this->trigger['beforeinsert']) &&
  400. \Base::instance()->call($this->trigger['beforeinsert'],
  401. [$this,$pkeys])===FALSE)
  402. return $this;
  403. foreach ($this->fields as $key=>&$field) {
  404. if ($field['pkey']) {
  405. $field['previous']=$field['value'];
  406. if (!$inc && $field['pdo_type']==\PDO::PARAM_INT &&
  407. empty($field['value']) && !$field['nullable'])
  408. $inc=$key;
  409. $filter.=($filter?' AND ':'').$this->db->quotekey($key).'=?';
  410. $nkeys[$nctr+1]=[$field['value'],$field['pdo_type']];
  411. $nctr++;
  412. }
  413. if ($field['changed'] && $key!=$inc) {
  414. $fields.=($actr?',':'').$this->db->quotekey($key);
  415. $values.=($actr?',':'').'?';
  416. $args[$actr+1]=[$field['value'],$field['pdo_type']];
  417. $actr++;
  418. $ckeys[]=$key;
  419. }
  420. }
  421. if ($fields) {
  422. $add=$aik='';
  423. if ($this->engine=='pgsql' && !empty($pkeys)) {
  424. $names=array_keys($pkeys);
  425. $aik=end($names);
  426. $add=' RETURNING '.$this->db->quotekey($aik);
  427. }
  428. $lID=$this->db->exec(
  429. (preg_match('/mssql|dblib|sqlsrv/',$this->engine) &&
  430. array_intersect(array_keys($pkeys),$ckeys)?
  431. 'SET IDENTITY_INSERT '.$this->table.' ON;':'').
  432. 'INSERT INTO '.$this->table.' ('.$fields.') '.
  433. 'VALUES ('.$values.')'.$add,$args
  434. );
  435. if ($this->engine=='pgsql' && $lID && $aik)
  436. $this->_id=$lID[0][$aik];
  437. elseif ($this->engine!='oci')
  438. $this->_id=$this->db->lastinsertid();
  439. // Reload to obtain default and auto-increment field values
  440. if ($reload=(($inc && $this->_id) || $filter))
  441. $this->load($inc?
  442. [$inc.'=?',$this->db->value(
  443. $this->fields[$inc]['pdo_type'],$this->_id)]:
  444. [$filter,$nkeys]);
  445. if (isset($this->trigger['afterinsert']))
  446. \Base::instance()->call($this->trigger['afterinsert'],
  447. [$this,$pkeys]);
  448. // reset changed flag after calling afterinsert
  449. if (!$reload)
  450. foreach ($this->fields as $key=>&$field) {
  451. $field['changed']=FALSE;
  452. $field['initial']=$field['value'];
  453. unset($field);
  454. }
  455. }
  456. return $this;
  457. }
  458. /**
  459. * Update current record
  460. * @return static
  461. **/
  462. function update() {
  463. $args=[];
  464. $ctr=0;
  465. $pairs='';
  466. $filter='';
  467. $pkeys=[];
  468. foreach ($this->fields as $key=>$field)
  469. if ($field['pkey'])
  470. $pkeys[$key]=$field['previous'];
  471. if (isset($this->trigger['beforeupdate']) &&
  472. \Base::instance()->call($this->trigger['beforeupdate'],
  473. [$this,$pkeys])===FALSE)
  474. return $this;
  475. foreach ($this->fields as $key=>$field)
  476. if ($field['changed']) {
  477. $pairs.=($pairs?',':'').$this->db->quotekey($key).'=?';
  478. $args[++$ctr]=[$field['value'],$field['pdo_type']];
  479. }
  480. foreach ($this->fields as $key=>$field)
  481. if ($field['pkey']) {
  482. $filter.=($filter?' AND ':' WHERE ').
  483. $this->db->quotekey($key).'=?';
  484. $args[++$ctr]=[$field['previous'],$field['pdo_type']];
  485. }
  486. if ($pairs) {
  487. $sql='UPDATE '.$this->table.' SET '.$pairs.$filter;
  488. $this->db->exec($sql,$args);
  489. }
  490. if (isset($this->trigger['afterupdate']))
  491. \Base::instance()->call($this->trigger['afterupdate'],
  492. [$this,$pkeys]);
  493. // reset changed flag after calling afterupdate
  494. foreach ($this->fields as $key=>&$field) {
  495. $field['changed']=FALSE;
  496. $field['initial']=$field['value'];
  497. unset($field);
  498. }
  499. return $this;
  500. }
  501. /**
  502. * Delete current record
  503. * @return int
  504. * @param $quick bool
  505. * @param $filter string|array
  506. **/
  507. function erase($filter=NULL,$quick=TRUE) {
  508. if (isset($filter)) {
  509. if (!$quick) {
  510. $out=0;
  511. foreach ($this->find($filter) as $mapper)
  512. $out+=$mapper->erase();
  513. return $out;
  514. }
  515. $args=[];
  516. if (is_array($filter)) {
  517. $args=isset($filter[1]) && is_array($filter[1])?
  518. $filter[1]:
  519. array_slice($filter,1,NULL,TRUE);
  520. $args=is_array($args)?$args:[1=>$args];
  521. list($filter)=$filter;
  522. }
  523. return $this->db->
  524. exec('DELETE FROM '.$this->table.
  525. ($filter?' WHERE '.$filter:'').';',$args);
  526. }
  527. $args=[];
  528. $ctr=0;
  529. $filter='';
  530. $pkeys=[];
  531. foreach ($this->fields as $key=>&$field) {
  532. if ($field['pkey']) {
  533. $filter.=($filter?' AND ':'').$this->db->quotekey($key).'=?';
  534. $args[$ctr+1]=[$field['previous'],$field['pdo_type']];
  535. $pkeys[$key]=$field['previous'];
  536. $ctr++;
  537. }
  538. $field['value']=NULL;
  539. $field['changed']=(bool)$field['default'];
  540. if ($field['pkey'])
  541. $field['previous']=NULL;
  542. unset($field);
  543. }
  544. foreach ($this->adhoc as &$field) {
  545. $field['value']=NULL;
  546. unset($field);
  547. }
  548. parent::erase();
  549. if (isset($this->trigger['beforeerase']) &&
  550. \Base::instance()->call($this->trigger['beforeerase'],
  551. [$this,$pkeys])===FALSE)
  552. return 0;
  553. $out=$this->db->
  554. exec('DELETE FROM '.$this->table.' WHERE '.$filter.';',$args);
  555. if (isset($this->trigger['aftererase']))
  556. \Base::instance()->call($this->trigger['aftererase'],
  557. [$this,$pkeys]);
  558. return $out;
  559. }
  560. /**
  561. * Reset cursor
  562. * @return NULL
  563. **/
  564. function reset() {
  565. foreach ($this->fields as &$field) {
  566. $field['value']=NULL;
  567. $field['initial']=NULL;
  568. $field['changed']=FALSE;
  569. if ($field['pkey'])
  570. $field['previous']=NULL;
  571. unset($field);
  572. }
  573. foreach ($this->adhoc as &$field) {
  574. $field['value']=NULL;
  575. unset($field);
  576. }
  577. parent::reset();
  578. }
  579. /**
  580. * Hydrate mapper object using hive array variable
  581. * @return NULL
  582. * @param $var array|string
  583. * @param $func callback
  584. **/
  585. function copyfrom($var,$func=NULL) {
  586. if (is_string($var))
  587. $var=\Base::instance()->$var;
  588. if ($func)
  589. $var=call_user_func($func,$var);
  590. foreach ($var as $key=>$val)
  591. if (in_array($key,array_keys($this->fields)))
  592. $this->set($key,$val);
  593. }
  594. /**
  595. * Populate hive array variable with mapper fields
  596. * @return NULL
  597. * @param $key string
  598. **/
  599. function copyto($key) {
  600. $var=&\Base::instance()->ref($key);
  601. foreach ($this->fields+$this->adhoc as $key=>$field)
  602. $var[$key]=$field['value'];
  603. }
  604. /**
  605. * Return schema and, if the first argument is provided, update it
  606. * @return array
  607. * @param $fields NULL|array
  608. **/
  609. function schema($fields=null) {
  610. if ($fields)
  611. $this->fields = $fields;
  612. return $this->fields;
  613. }
  614. /**
  615. * Return field names
  616. * @return array
  617. * @param $adhoc bool
  618. **/
  619. function fields($adhoc=TRUE) {
  620. return array_keys($this->fields+($adhoc?$this->adhoc:[]));
  621. }
  622. /**
  623. * Return TRUE if field is not nullable
  624. * @return bool
  625. * @param $field string
  626. **/
  627. function required($field) {
  628. return isset($this->fields[$field]) &&
  629. !$this->fields[$field]['nullable'];
  630. }
  631. /**
  632. * Retrieve external iterator for fields
  633. * @return object
  634. **/
  635. function getiterator() {
  636. return new \ArrayIterator($this->cast());
  637. }
  638. /**
  639. * Assign alias for table
  640. * @param $alias string
  641. **/
  642. function alias($alias) {
  643. $this->as=$alias;
  644. return $this;
  645. }
  646. /**
  647. * Instantiate class
  648. * @param $db \DB\SQL
  649. * @param $table string
  650. * @param $fields array|string
  651. * @param $ttl int|array
  652. **/
  653. function __construct(\DB\SQL $db,$table,$fields=NULL,$ttl=60) {
  654. $this->db=$db;
  655. $this->engine=$db->driver();
  656. if ($this->engine=='oci')
  657. $table=strtoupper($table);
  658. $this->source=$table;
  659. $this->table=$this->db->quotekey($table);
  660. $this->fields=$db->schema($table,$fields,$ttl);
  661. $this->reset();
  662. }
  663. }