PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/class/AppObject.php

http://github.com/ethna/ethna
PHP | 1657 lines | 925 code | 161 blank | 571 comment | 242 complexity | db831ea14439b0b6117998303249718e MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. // vim: foldmethod=marker
  3. /**
  4. * AppObject.php
  5. *
  6. * @author Masaki Fujimoto <fujimoto@php.net>
  7. * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  8. * @package Ethna
  9. * @version $Id: 34811a223f106bb88158be4783391e12bdc8b8f2 $
  10. */
  11. // {{{ Ethna_AppObject
  12. /**
  13. * ?????????????????????
  14. *
  15. * @author Masaki Fujimoto <fujimoto@php.net>
  16. * @access public
  17. * @package Ethna
  18. * @todo ?????????
  19. * @todo remove dependency on PEAR::DB
  20. * @todo quoteidentifier ? Ethna_AppSQL ????????
  21. */
  22. class Ethna_AppObject
  23. {
  24. // {{{ properties
  25. /**#@+
  26. * @access private
  27. */
  28. /** @protected object Ethna_Backend backend?????? */
  29. protected $backend;
  30. /** @protected object Ethna_Config ???????? */
  31. protected $config;
  32. /** @protected object Ethna_I18N i18n?????? */
  33. protected $i18n;
  34. /** @protected object Ethna_ActionForm ??????????????? */
  35. protected $action_form;
  36. /** @protected object Ethna_ActionForm ???????????????(???) */
  37. protected $af;
  38. /** @protected object Ethna_Session ??????????? */
  39. protected $session;
  40. /** @protected string DB???????? */
  41. protected $db_prefix = null;
  42. /** @protected array ???????????DB??????????????*/
  43. protected $table_def = null;
  44. /** @protected array ????????????????????????? */
  45. protected $prop_def = null;
  46. /** @protected array ?????????????????????? */
  47. protected $prop = null;
  48. /** @protected array ?????(??????) */
  49. protected $prop_backup = null;
  50. /** @protected int ????????????????(sec) */
  51. protected $prop_def_cache_lifetime = 86400;
  52. /** @protected array ????????? */
  53. protected $id_def = null;
  54. /** @protected int ??????ID (??????????) */
  55. protected $id = null;
  56. /**#@-*/
  57. // }}}
  58. // {{{ Ethna_AppObject
  59. /**
  60. * Ethna_AppObject???????????
  61. *
  62. * @access public
  63. * @param object Ethna_Backend $backend Ethna_Backend??????
  64. * @param mixed $key_type ????????????????
  65. * (?????????????????)
  66. * @param mixed $key ????????????????
  67. * @param array $prop ?????(??????)??
  68. * @return mixed 0:???? -1:??/???????? Ethna_Error:???
  69. */
  70. public function __construct($backend, $key_type = null, $key = null, $prop = null)
  71. {
  72. $this->backend = $backend;
  73. $this->config = $backend->getConfig();
  74. $this->action_form = $backend->getActionForm();
  75. $this->af = $this->action_form;
  76. $this->session = $backend->getSession();
  77. $ctl = $backend->getController();
  78. // DB?????????
  79. $db_list = $this->_getDBList();
  80. if (Ethna::isError($db_list)) {
  81. return $db_list;
  82. } else if (is_null($db_list['rw'])) {
  83. return Ethna::raiseError(
  84. "Ethna_AppObject????????????????????",
  85. E_DB_NODSN);
  86. }
  87. $this->my_db_rw = $db_list['rw'];
  88. $this->my_db_ro = $db_list['ro'];
  89. // XXX: app obj?db type???????????
  90. $this->my_db_type = $this->my_db_rw->getType();
  91. // ??????????
  92. // ???????????????????primary?true
  93. if (is_null($this->table_def)) {
  94. $this->table_def = $this->_getTableDef();
  95. }
  96. if (is_string($this->table_def)) {
  97. $this->table_def = array($this->table_def => array('primary' => true));
  98. }
  99. // ???????(??????????)????
  100. // ???????????????????????
  101. if (is_null($this->prop_def)) {
  102. $this->prop_def = $this->_getPropDef();
  103. }
  104. // ???????????????
  105. foreach (array_keys($this->prop_def) as $k) {
  106. if (isset($this->prop_def[$k]['primary']) == false) {
  107. $this->prop_def[$k]['primary'] = false;
  108. }
  109. }
  110. // ??????????????????
  111. foreach ($this->prop_def as $k => $v) {
  112. if ($v['primary'] == false) {
  113. continue;
  114. }
  115. if (is_null($this->id_def)) {
  116. $this->id_def = $k;
  117. } else if (is_array($this->id_def)) {
  118. $this->id_def[] = $k;
  119. } else { // scalar ???
  120. $this->id_def = array($this->id_def, $k);
  121. }
  122. }
  123. // ?????????
  124. if (is_null($key_type) && is_null($key) && is_null($prop)) {
  125. // perhaps for adding object
  126. return 0;
  127. }
  128. // ???????
  129. // $key_type, $key ???????DB????????????
  130. // $prop ????????????????
  131. if (is_null($prop)) {
  132. $this->_setPropByDB($key_type, $key);
  133. } else {
  134. $this->_setPropByValue($prop);
  135. }
  136. $this->prop_backup = $this->prop;
  137. // ?????????????
  138. if (is_array($this->id_def)) {
  139. $this->id = array();
  140. foreach ($this->id_def as $k) {
  141. $this->id[] = $this->prop[$k];
  142. }
  143. } else {
  144. $this->id = $this->prop[$this->id_def];
  145. }
  146. return 0;
  147. }
  148. // }}}
  149. // {{{ isValid
  150. /**
  151. * ????????????????
  152. * ????????????????????????????????
  153. *
  154. * @access public
  155. * @return bool true:?? false:??
  156. */
  157. function isValid()
  158. {
  159. if (is_array($this->id)) {
  160. return is_null($this->id[0]) ? false : true;
  161. } else {
  162. return is_null($this->id) ? false : true;
  163. }
  164. }
  165. // }}}
  166. // {{{ isActive
  167. /**
  168. * ???????????????????
  169. *
  170. * isValid()?????????????????????????????
  171. * isActive()????????????????????????????
  172. *
  173. * @access public
  174. * @return bool true:????? false:??????
  175. */
  176. function isActive()
  177. {
  178. if ($this->isValid() == false) {
  179. return false;
  180. }
  181. return $this->prop['state'] == OBJECT_STATE_ACTIVE ? true : false;
  182. }
  183. // }}}
  184. // {{{ getDef
  185. /**
  186. * ??????????????(?????)???
  187. *
  188. * @access public
  189. * @return array ??????????????
  190. */
  191. function getDef()
  192. {
  193. return $this->prop_def;
  194. }
  195. // }}}
  196. // {{{ getIdDef
  197. /**
  198. * ????????????
  199. *
  200. * @access public
  201. * @return mixed ????????????????
  202. */
  203. function getIdDef()
  204. {
  205. return $this->id_def;
  206. }
  207. // }}}
  208. // {{{ getId
  209. /**
  210. * ??????ID(primary key??)???
  211. *
  212. * @access public
  213. * @return mixed ??????ID
  214. */
  215. function getId()
  216. {
  217. return $this->id;
  218. }
  219. // }}}
  220. // {{{ get
  221. /**
  222. * ?????????????????(R)
  223. *
  224. * @access public
  225. * @param string $key ??????(????)
  226. * @return mixed ?????(?????)
  227. */
  228. function get($key)
  229. {
  230. if (isset($this->prop_def[$key]) == false) {
  231. trigger_error(sprintf("Unknown property [%s]", $key), E_USER_ERROR);
  232. return null;
  233. }
  234. if (isset($this->prop[$key])) {
  235. return $this->prop[$key];
  236. }
  237. return null;
  238. }
  239. // }}}
  240. // {{{ getName
  241. /**
  242. * ????????????????????
  243. * ?????????????????? (???????
  244. * ?????????????
  245. *
  246. * ????????????????
  247. *
  248. * @access public
  249. * @param string $key ?????(???)?
  250. * @return string ?????(???)????
  251. */
  252. function getName($key)
  253. {
  254. return $this->get($key);
  255. }
  256. // }}}
  257. /**
  258. * ??????????????(??)??????
  259. * ?????????????????? (???????
  260. * ?????????????
  261. *
  262. * @access public
  263. * @param string $key ?????(???)?
  264. * @return string ?????(???)????(??)
  265. */
  266. function getLongName($key)
  267. {
  268. return $this->get($key);
  269. }
  270. // }}}
  271. // {{{ getNameObject
  272. /**
  273. * ??????????????????????
  274. * ???? getName ???????????????????
  275. *
  276. * @access public
  277. * @return array ?????????????????
  278. */
  279. function getNameObject()
  280. {
  281. $object = array();
  282. foreach ($this->prop_def as $key => $elt) {
  283. $object[$elt['form_name']] = $this->getName($key);
  284. }
  285. return $object;
  286. }
  287. // }}}
  288. // {{{ set
  289. /**
  290. * ???????????(?????????)???????
  291. *
  292. * @access public
  293. * @param string $key ?????(???)?
  294. * @param string $value ??????
  295. */
  296. function set($key, $value)
  297. {
  298. if (isset($this->prop_def[$key]) == false) {
  299. trigger_error(sprintf("Unknown property [%s]", $key), E_USER_ERROR);
  300. return null;
  301. }
  302. $this->prop[$key] = $value;
  303. }
  304. // }}}
  305. // {{{ dump
  306. /**
  307. * ???????????????????????(???CSV????????)
  308. *
  309. * @access public
  310. * @param string $type ?????("csv"...)
  311. * @return string ?????(???????null)
  312. */
  313. function dump($type = "csv")
  314. {
  315. $method = "_dump_$type";
  316. if (method_exists($this, $method) == false) {
  317. return Ethna::raiseError("Undefined Method [%s]", E_APP_NOMETHOD, $method);
  318. }
  319. return $this->$method();
  320. }
  321. // }}}
  322. // {{{ importForm
  323. /**
  324. * ??????????????????????????
  325. *
  326. * @access public
  327. * @param int $option ??????????
  328. * OBJECT_IMPORT_IGNORE_NULL: ?????????????????????
  329. * OBJECT_IMPORT_CONVERT_NULL: ????????????????????????
  330. */
  331. function importForm($option = null)
  332. {
  333. foreach ($this->getDef() as $k => $def) {
  334. $value = $this->af->get($def['form_name']);
  335. if (is_null($value)) {
  336. // ??????????????????????
  337. if ($option == OBJECT_IMPORT_IGNORE_NULL) {
  338. // null?????
  339. continue;
  340. } else if ($option == OBJECT_IMPORT_CONVERT_NULL) {
  341. // ???????
  342. $value = '';
  343. }
  344. }
  345. $this->set($k, $value);
  346. }
  347. }
  348. // }}}
  349. // {{{ exportForm
  350. /**
  351. * ??????????????????????????
  352. *
  353. * @access public
  354. */
  355. function exportForm()
  356. {
  357. foreach ($this->getDef() as $k => $def) {
  358. $this->af->set($def['form_name'], $this->get($k));
  359. }
  360. }
  361. // }}}
  362. // {{{ add
  363. /**
  364. * ???????????(INSERT)
  365. *
  366. * @access public
  367. * @return mixed 0:???? Ethna_Error:???
  368. * @todo remove dependency on PEAR::DB
  369. */
  370. function add()
  371. {
  372. // primary key ??? sequence ????
  373. // next id???: (pgsql?????)
  374. // ??????????id???
  375. foreach (to_array($this->id_def) as $id_def) {
  376. if (isset($this->prop_def[$id_def]['seq'])
  377. && $this->prop_def[$id_def]['seq']) {
  378. // NOTE: ??app object????insert????????
  379. $next_id = $this->my_db_rw->getNextId(
  380. $this->prop_def[$id_def]['table'], $id_def);
  381. if ($next_id !== null && $next_id >= 0) {
  382. $this->prop[$id_def] = $next_id;
  383. }
  384. break;
  385. }
  386. }
  387. // INSERT ????????
  388. $sql = $this->_getSQL_Add();
  389. for ($i = 0; $i < 4; $i++) {
  390. $r = $this->my_db_rw->query($sql);
  391. // ?????? -> ???????????????
  392. if (Ethna::isError($r)) {
  393. if ($r->getCode() == E_DB_DUPENT) {
  394. // ??????????
  395. $duplicate_key_list = $this->_getDuplicateKeyList();
  396. if (Ethna::isError($duplicate_key_list)) {
  397. return $duplicate_key_list;
  398. }
  399. if (is_array($duplicate_key_list)
  400. && count($duplicate_key_list) > 0) {
  401. foreach ($duplicate_key_list as $k) {
  402. return Ethna::raiseNotice('Duplicate Key Error [%s]',
  403. E_APP_DUPENT, $k);
  404. }
  405. }
  406. } else {
  407. return $r;
  408. }
  409. } else {
  410. break;
  411. }
  412. }
  413. if ($i == 4) {
  414. // cannot be reached
  415. return Ethna::raiseError('Cannot detect Duplicate key Error', E_GENERAL);
  416. }
  417. // last insert id???: (mysql, sqlite??)
  418. // primary key ? 'seq' ??????(???)?????????
  419. $insert_id = $this->my_db_rw->getInsertId();
  420. if ($insert_id !== null && $insert_id >= 0) {
  421. foreach (to_array($this->id_def) as $id_def) {
  422. if (isset($this->prop_def[$id_def]['seq'])
  423. && $this->prop_def[$id_def]['seq']) {
  424. $this->prop[$id_def] = $insert_id;
  425. break;
  426. }
  427. }
  428. }
  429. // ID(Primary Key)?????
  430. if (is_array($this->id_def)) {
  431. $this->id = array();
  432. foreach ($this->id_def as $k) {
  433. $this->id[] = $this->prop[$k];
  434. }
  435. } else if (isset($this->prop[$this->id_def])) {
  436. $this->id = $this->prop[$this->id_def];
  437. } else {
  438. trigger_error("primary key is missing", E_USER_ERROR);
  439. }
  440. // ??????/???????
  441. $this->prop_backup = $this->prop;
  442. $this->_clearPropCache();
  443. return 0;
  444. }
  445. // }}}
  446. // {{{ update
  447. /**
  448. * ???????????(UPDATE)
  449. *
  450. * @access public
  451. * @return mixed 0:???? Ethna_Error:???
  452. * @todo remove dependency on PEAR::DB
  453. */
  454. function update()
  455. {
  456. $sql = $this->_getSQL_Update();
  457. // ?????? -> ???????????????(4?)
  458. for ($i = 0; $i < 4; $i++) { // magic number
  459. $r = $this->my_db_rw->query($sql);
  460. if (Ethna::isError($r)) {
  461. if ($r->getCode() == E_DB_DUPENT) {
  462. // ??????????
  463. $duplicate_key_list = $this->_getDuplicateKeyList();
  464. if (Ethna::isError($duplicate_key_list)) {
  465. return $duplicate_key_list;
  466. }
  467. if (is_array($duplicate_key_list)
  468. && count($duplicate_key_list) > 0) {
  469. foreach ($duplicate_key_list as $k) {
  470. return Ethna::raiseNotice('Duplicate Key Error [%s]',
  471. E_APP_DUPENT, $k);
  472. }
  473. }
  474. } else {
  475. return $r;
  476. }
  477. } else {
  478. break;
  479. }
  480. }
  481. if ($i == 4) {
  482. // cannot be reached
  483. return Ethna::raiseError('Cannot detect Duplicate key Error', E_GENERAL);
  484. }
  485. $affected_rows = $this->my_db_rw->affectedRows();
  486. if ($affected_rows <= 0) {
  487. $this->backend->log(LOG_DEBUG, "update query with 0 updated rows");
  488. }
  489. // ??????/???????
  490. $this->prop_backup = $this->prop;
  491. $this->_clearPropCache();
  492. return 0;
  493. }
  494. // }}}
  495. // {{{ replace
  496. /**
  497. * ???????????
  498. *
  499. * MySQL?REPLACE???????????(add()????????????
  500. * update()???)
  501. *
  502. * @access public
  503. * @return mixed 0:???? >0:??????ID(???) Ethna_Error:???
  504. * @todo remove dependency on PEAR::DB
  505. */
  506. function replace()
  507. {
  508. $sql = $this->_getSQL_Select($this->getIdDef(), $this->getId());
  509. // ???????????????(4?)
  510. for ($i = 0; $i < 3; $i++) { // magic number
  511. $r = $this->my_db_rw->query($sql);
  512. if (Ethna::isError($r)) {
  513. return $r;
  514. }
  515. $n = $r->numRows();
  516. if ($n > 0) {
  517. $r = $this->update();
  518. return $r;
  519. } else {
  520. $r = $this->add();
  521. if (Ethna::isError($r) == false) {
  522. return $r;
  523. } else if ($r->getCode() != E_APP_DUPENT) {
  524. return $r;
  525. }
  526. }
  527. }
  528. return $r;
  529. }
  530. // }}}
  531. // {{{ remove
  532. /**
  533. * ??????(????)?????
  534. *
  535. * @access public
  536. * @return mixed 0:???? Ethna_Error:???
  537. * @todo remove dependency on PEAR::DB
  538. */
  539. function remove()
  540. {
  541. $sql = $this->_getSQL_Remove();
  542. $r = $this->my_db_rw->query($sql);
  543. if (Ethna::isError($r)) {
  544. return $r;
  545. }
  546. // ?????/??????/????????
  547. $this->id = $this->prop = $this->prop_backup = null;
  548. $this->_clearPropCache();
  549. return 0;
  550. }
  551. // }}}
  552. // {{{ searchId
  553. /**
  554. * ??????ID(??????????)?????
  555. *
  556. * @access public
  557. * @param array $filter WHERE????(???????????????????Ethna_AppSearchObject???)
  558. * @param array $order ?????????
  559. * (?????????????????? OBJECT_SORT_ASC, ???????OBJECT_SORT_DESC)
  560. * @param int $offset ???????????
  561. * @param int $count ???????
  562. * @return mixed array(0 => ????????????,
  563. * 1 => $offset, $count?????????????????ID??)
  564. * Ethna_Error:???
  565. * TODO: remove dependency on PEAR::DB
  566. */
  567. function searchId($filter = null, $order = null, $offset = null, $count = null)
  568. {
  569. // ????????????
  570. if (is_null($offset) == false || is_null($count) == false) {
  571. $sql = $this->_getSQL_SearchLength($filter);
  572. $r = $this->my_db_ro->query($sql);
  573. if (Ethna::isError($r)) {
  574. return $r;
  575. }
  576. $row = $this->my_db_ro->fetchRow($r, DB_FETCHMODE_ASSOC);
  577. $length = $row['id_count'];
  578. } else {
  579. $length = null;
  580. }
  581. $id_list = array();
  582. $sql = $this->_getSQL_SearchId($filter, $order, $offset, $count);
  583. $r = $this->my_db_ro->query($sql);
  584. if (Ethna::isError($r)) {
  585. return $r;
  586. }
  587. $n = $r->numRows();
  588. for ($i = 0; $i < $n; $i++) {
  589. $row = $this->my_db_ro->fetchRow($r, DB_FETCHMODE_ASSOC);
  590. // ????????1?????????????
  591. if (is_array($this->id_def) == false) {
  592. $row = $row[$this->id_def];
  593. }
  594. $id_list[] = $row;
  595. }
  596. if (is_null($length)) {
  597. $length = count($id_list);
  598. }
  599. return array($length, $id_list);
  600. }
  601. // }}}
  602. // {{{ searchProp
  603. /**
  604. * ???????????(????)?????
  605. *
  606. * @access public
  607. * @param array $keys ?????????(????)
  608. * @param array $filter WHERE????(???????????????????Ethna_AppSearchObject???)
  609. * @param array $order ?????????
  610. * (?????????????????? OBJECT_SORT_ASC, ???????OBJECT_SORT_DESC)
  611. * @param int $offset ???????????
  612. * @param int $count ???????
  613. * @return mixed array(0 => ????????????,
  614. * 1 => $offset, $count????????????????????????)
  615. * Ethna_Error:???
  616. * TODO: remove dependency on PEAR::DB
  617. */
  618. function searchProp($keys = null, $filter = null, $order = null,
  619. $offset = null, $count = null)
  620. {
  621. // ????????????
  622. if (is_null($offset) == false || is_null($count) == false) {
  623. $sql = $this->_getSQL_SearchLength($filter);
  624. $r = $this->my_db_ro->query($sql);
  625. if (Ethna::isError($r)) {
  626. return $r;
  627. }
  628. $row = $this->my_db_ro->fetchRow($r, DB_FETCHMODE_ASSOC);
  629. $length = $row['id_count'];
  630. } else {
  631. $length = null;
  632. }
  633. $prop_list = array();
  634. $sql = $this->_getSQL_SearchProp($keys, $filter, $order, $offset, $count);
  635. $r = $this->my_db_ro->query($sql);
  636. if (Ethna::isError($r)) {
  637. return $r;
  638. }
  639. $n = $r->numRows();
  640. for ($i = 0; $i < $n; $i++) {
  641. $row = $this->my_db_ro->fetchRow($r, DB_FETCHMODE_ASSOC);
  642. $prop_list[] = $row;
  643. }
  644. if (is_null($length)) {
  645. $length = count($prop_list);
  646. }
  647. return array($length, $prop_list);
  648. }
  649. // }}}
  650. // {{{ _setDefault
  651. /**
  652. * ??????????????????????????????
  653. *
  654. * ???????????????????????????????????
  655. * ????????????????????????
  656. *
  657. * @access protected
  658. * @param mixed $key_type ?????
  659. * @param mixed $key ????
  660. * @return int 0:????
  661. */
  662. function _setDefault($key_type, $key)
  663. {
  664. return 0;
  665. }
  666. // }}}
  667. // {{{ _setPropByDB
  668. /**
  669. * ????????????DB??????
  670. *
  671. * @access private
  672. * @param mixed $key_type ?????
  673. * @param mixed $key ????
  674. * TODO: depend on PEAR::DB
  675. */
  676. function _setPropByDB($key_type, $key)
  677. {
  678. global $_ETHNA_APP_OBJECT_CACHE;
  679. $key_type = to_array($key_type);
  680. $key = to_array($key);
  681. if (count($key_type) != count($key)) {
  682. trigger_error(sprintf("Unmatched key_type & key length [%d-%d]",
  683. count($key_type), count($key)), E_USER_ERROR);
  684. return;
  685. }
  686. foreach ($key_type as $elt) {
  687. if (isset($this->prop_def[$elt]) == false) {
  688. trigger_error("Invalid key_type [$elt]", E_USER_ERROR);
  689. return;
  690. }
  691. }
  692. // ?????????
  693. $class_name = strtolower(get_class($this));
  694. if (is_array($_ETHNA_APP_OBJECT_CACHE) == false
  695. || array_key_exists($class_name, $_ETHNA_APP_OBJECT_CACHE) == false) {
  696. $_ETHNA_APP_OBJECT_CACHE[$class_name] = array();
  697. }
  698. $cache_key = serialize(array($key_type, $key));
  699. if (array_key_exists($cache_key, $_ETHNA_APP_OBJECT_CACHE[$class_name])) {
  700. $this->prop = $_ETHNA_APP_OBJECT_CACHE[$class_name][$cache_key];
  701. return;
  702. }
  703. // SQL???
  704. $sql = $this->_getSQL_Select($key_type, $key);
  705. // ???????
  706. $r = $this->my_db_ro->query($sql);
  707. if (Ethna::isError($r)) {
  708. return;
  709. }
  710. $n = $r->numRows();
  711. if ($n == 0) {
  712. // try default
  713. if ($this->_setDefault($key_type, $key) == false) {
  714. // nop
  715. }
  716. return;
  717. } else if ($n > 1) {
  718. trigger_error("Invalid key (multiple rows found) [$key]", E_USER_ERROR);
  719. return;
  720. }
  721. $this->prop = $this->my_db_ro->fetchRow($r, DB_FETCHMODE_ASSOC);
  722. // ???????????
  723. $_ETHNA_APP_OBJECT_CACHE[$class_name][$cache_key] = $this->prop;
  724. }
  725. // }}}
  726. // {{{ _setPropByValue
  727. /**
  728. * ???????????????????????
  729. *
  730. * @access private
  731. * @param array $prop ???????
  732. */
  733. function _setPropByValue($prop)
  734. {
  735. $def = $this->getDef();
  736. foreach ($def as $key => $value) {
  737. if ($value['primary'] && isset($prop[$key]) == false) {
  738. // ????????????
  739. trigger_error("primary key is not identical", E_USER_ERROR);
  740. }
  741. $this->prop[$key] = $prop[$key];
  742. }
  743. }
  744. // }}}
  745. // {{{ _getPrimaryTable
  746. /**
  747. * ?????????????????????
  748. *
  749. * @access private
  750. * @return string ?????????????????
  751. */
  752. function _getPrimaryTable()
  753. {
  754. $tables = array_keys($this->table_def);
  755. $table = $tables[0];
  756. return $table;
  757. }
  758. // }}}
  759. // {{{ _getDuplicateKeyList
  760. /**
  761. * ?????????
  762. *
  763. * @access private
  764. * @return mixed 0:???? Ethna_Error:??? array:?????????????
  765. * TODO: depend on PEAR::DB
  766. */
  767. function _getDuplicateKeyList()
  768. {
  769. $duplicate_key_list = array();
  770. // ?????????????????NULL?????????????
  771. $check_pkey = true;
  772. foreach (to_array($this->id_def) as $k) {
  773. if (isset($this->prop[$k]) == false || is_null($this->prop[$k])) {
  774. $check_pkey = false;
  775. break;
  776. }
  777. }
  778. // ????????multi columns??????????
  779. if ($check_pkey) {
  780. $sql = $this->_getSQL_Duplicate($this->id_def);
  781. $r = $this->my_db_rw->query($sql);
  782. if (Ethna::isError($r)) {
  783. return $r;
  784. } else if ($r->numRows() > 0) {
  785. // we can overwrite $key_list here
  786. $duplicate_key_list = to_array($this->id_def);
  787. }
  788. }
  789. // ??????
  790. foreach ($this->prop_def as $k => $v) {
  791. if ($v['primary'] == true || $v['key'] == false) {
  792. continue;
  793. }
  794. $sql = $this->_getSQL_Duplicate($k);
  795. $r = $this->my_db_rw->query($sql);
  796. if (Ethna::isError($r)) {
  797. return $r;
  798. } else if ($r->NumRows() > 0) {
  799. $duplicate_key_list[] = $k;
  800. }
  801. }
  802. if (count($duplicate_key_list) > 0) {
  803. return $duplicate_key_list;
  804. } else {
  805. return 0;
  806. }
  807. }
  808. // }}}
  809. // {{{ _getSQL_Select
  810. /**
  811. * ????????????????SQL??????
  812. *
  813. * @access private
  814. * @param array $key_type ????????????(???)???
  815. * @param array $key $key_type?????????
  816. * @return string SELECT?
  817. */
  818. function _getSQL_Select($key_type, $key)
  819. {
  820. $key_type = to_array($key_type);
  821. if (is_null($key)) {
  822. // add()?
  823. $key = array();
  824. for ($i = 0; $i < count($key_type); $i++) {
  825. $key[$i] = null;
  826. }
  827. } else {
  828. $key = to_array($key);
  829. }
  830. // SQL?????
  831. Ethna_AppSQL::escapeSQL($key, $this->my_db_type);
  832. $tables = implode(',',
  833. $this->my_db_ro->quoteIdentifier(array_keys($this->table_def)));
  834. $columns = implode(',',
  835. $this->my_db_ro->quoteIdentifier(array_keys($this->prop_def)));
  836. // ????
  837. $condition = null;
  838. for ($i = 0; $i < count($key_type); $i++) {
  839. if (is_null($condition)) {
  840. $condition = "WHERE ";
  841. } else {
  842. $condition .= " AND ";
  843. }
  844. $condition .= Ethna_AppSQL::getCondition(
  845. $this->my_db_ro->quoteIdentifier($key_type[$i]), $key[$i]);
  846. }
  847. $sql = "SELECT $columns FROM $tables $condition";
  848. return $sql;
  849. }
  850. // }}}
  851. // {{{ _getSQL_Add
  852. /**
  853. * ???????????SQL??????
  854. *
  855. * @access private
  856. * @return string ??????????????INSERT?
  857. */
  858. function _getSQL_Add()
  859. {
  860. $tables = implode(',',
  861. $this->my_db_rw->quoteIdentifier(array_keys($this->table_def)));
  862. $key_list = array();
  863. $set_list = array();
  864. $prop_arg_list = $this->prop;
  865. Ethna_AppSQL::escapeSQL($prop_arg_list, $this->my_db_type);
  866. foreach ($this->prop_def as $k => $v) {
  867. if (isset($prop_arg_list[$k]) == false) {
  868. continue;
  869. }
  870. $key_list[] = $this->my_db_rw->quoteIdentifier($k);
  871. $set_list[] = $prop_arg_list[$k];
  872. }
  873. $key_list = implode(', ', $key_list);
  874. $set_list = implode(', ', $set_list);
  875. $sql = "INSERT INTO $tables ($key_list) VALUES ($set_list)";
  876. return $sql;
  877. }
  878. // }}}
  879. // {{{ _getSQL_Update
  880. /**
  881. * ????????????????SQL??????
  882. *
  883. * @access private
  884. * @return ???????????????????UPDATE?
  885. */
  886. function _getSQL_Update()
  887. {
  888. $tables = implode(',',
  889. $this->my_db_rw->quoteIdentifier(array_keys($this->table_def)));
  890. // SET???
  891. $set_list = "";
  892. $prop_arg_list = $this->prop;
  893. Ethna_AppSQL::escapeSQL($prop_arg_list, $this->my_db_type);
  894. foreach ($this->prop_def as $k => $v) {
  895. if ($set_list != "") {
  896. $set_list .= ",";
  897. }
  898. $set_list .= sprintf("%s=%s",
  899. $this->my_db_rw->quoteIdentifier($k),
  900. $prop_arg_list[$k]);
  901. }
  902. // ????(primary key)
  903. $condition = null;
  904. foreach (to_array($this->id_def) as $k) {
  905. if (is_null($condition)) {
  906. $condition = "WHERE ";
  907. } else {
  908. $condition .= " AND ";
  909. }
  910. $v = $this->prop_backup[$k]; // equals to $this->id
  911. Ethna_AppSQL::escapeSQL($v, $this->my_db_type);
  912. $condition .= Ethna_AppSQL::getCondition(
  913. $this->my_db_rw->quoteIdentifier($k), $v);
  914. }
  915. $sql = "UPDATE $tables SET $set_list $condition";
  916. return $sql;
  917. }
  918. // }}}
  919. // {{{ _getSQL_Remove
  920. /**
  921. * ???????????SQL??????
  922. *
  923. * @access private
  924. * @return string ??????????????DELETE?
  925. */
  926. function _getSQL_Remove()
  927. {
  928. $tables = implode(',',
  929. $this->my_db_rw->quoteIdentifier(array_keys($this->table_def)));
  930. // ????(primary key)
  931. $condition = null;
  932. foreach (to_array($this->id_def) as $k) {
  933. if (is_null($condition)) {
  934. $condition = "WHERE ";
  935. } else {
  936. $condition .= " AND ";
  937. }
  938. $v = $this->prop_backup[$k]; // equals to $this->id
  939. Ethna_AppSQL::escapeSQL($v, $this->my_db_type);
  940. $condition .= Ethna_AppSQL::getCondition(
  941. $this->my_db_rw->quoteIdentifier($k), $v);
  942. }
  943. if (is_null($condition)) {
  944. trigger_error("DELETE with no conditon", E_USER_ERROR);
  945. return null;
  946. }
  947. $sql = "DELETE FROM $tables $condition";
  948. return $sql;
  949. }
  950. // }}}
  951. // {{{ _getSQL_Duplicate
  952. /**
  953. * ???????????????????????SQL??????
  954. *
  955. * @access private
  956. * @param mixed $key ?????????????????
  957. * @return string ??????????????SELECT?
  958. */
  959. function _getSQL_Duplicate($key)
  960. {
  961. $tables = implode(',',
  962. $this->my_db_ro->quoteIdentifier(array_keys($this->table_def)));
  963. $columns = implode(',',
  964. $this->my_db_ro->quoteIdentifier(array_keys($this->prop_def)));
  965. $condition = null;
  966. // ????(?????????????????????????)
  967. if (is_null($this->id) == false) {
  968. $primary_value = to_array($this->getId());
  969. $n = 0;
  970. foreach (to_array($this->id_def) as $k) {
  971. if (is_null($condition)) {
  972. $condition = "WHERE ";
  973. } else {
  974. $condition .= " AND ";
  975. }
  976. $value = $primary_value[$n];
  977. Ethna_AppSQL::escapeSQL($value, $this->my_db_type);
  978. $condition .= Ethna_AppSQL::getCondition(
  979. $this->my_db_ro->quoteIdentifier($k), $value, OBJECT_CONDITION_NE);
  980. $n++;
  981. }
  982. }
  983. foreach (to_array($key) as $k) {
  984. if (is_null($condition)) {
  985. $condition = "WHERE ";
  986. } else {
  987. $condition .= " AND ";
  988. }
  989. $v = $this->prop[$k];
  990. Ethna_AppSQL::escapeSQL($v, $this->my_db_type);
  991. $condition .= Ethna_AppSQL::getCondition(
  992. $this->my_db_ro->quoteIdentifier($k), $v);
  993. }
  994. $sql = "SELECT $columns FROM $tables $condition";
  995. return $sql;
  996. }
  997. // }}}
  998. // {{{ _getSQL_SearchLength
  999. /**
  1000. * ??????????(offset, count??)?????SQL??????
  1001. *
  1002. * @access private
  1003. * @param array $filter WHERE????(???????????????????Ethna_AppSearchObject???)
  1004. * @return string ????????????SELECT?
  1005. * @todo my_db_type??????
  1006. */
  1007. function _getSQL_SearchLength($filter)
  1008. {
  1009. // ?????????????????
  1010. $tables = implode(',',
  1011. $this->my_db_ro->quoteIdentifier(array_keys($this->table_def)));
  1012. // ??????????????????????
  1013. // ??????????????????
  1014. // ????? _SQLPlugin_SearchTable ????
  1015. if ($this->_isAdditionalField($filter)) {
  1016. $tables .= " " . $this->_SQLPlugin_SearchTable();
  1017. }
  1018. $id_def = to_array($this->id_def);
  1019. // ?????.?????????
  1020. // ?????????????????
  1021. $column_id = $this->my_db_ro->quoteIdentifier($this->_getPrimaryTable())
  1022. . "." . $this->my_db_ro->quoteIdentifier($id_def[0]);
  1023. $id_count = $this->my_db_ro->quoteIdentifier('id_count');
  1024. $condition = $this->_getSQL_SearchCondition($filter);
  1025. if ($this->my_db_type === 'sqlite') {
  1026. $sql = "SELECT COUNT(*) AS $id_count FROM "
  1027. . " (SELECT DISTINCT $column_id FROM $tables $condition)";
  1028. } else {
  1029. $sql = "SELECT COUNT(DISTINCT $column_id) AS $id_count "
  1030. . "FROM $tables $condition";
  1031. }
  1032. return $sql;
  1033. }
  1034. // }}}
  1035. // {{{ _getSQL_SearchId
  1036. /**
  1037. * ??????ID(????????)?????SQL??????
  1038. *
  1039. * @access private
  1040. * @param array $filter WHERE????(???????????????????Ethna_AppSearchObject???)
  1041. * @param array $order ?????????
  1042. * (?????????????????? OBJECT_SORT_ASC, ???????OBJECT_SORT_DESC)
  1043. * @param int $offset ???????????
  1044. * @param int $count ???????
  1045. * @return string ???????????SELECT?
  1046. */
  1047. function _getSQL_SearchId($filter, $order, $offset, $count)
  1048. {
  1049. // ????
  1050. $tables = implode(',',
  1051. $this->my_db_ro->quoteIdentifier(array_keys($this->table_def)));
  1052. if ($this->_isAdditionalField($filter)
  1053. || $this->_isAdditionalField($order)) {
  1054. $tables .= " " . $this->_SQLPlugin_SearchTable();
  1055. }
  1056. $column_id = "";
  1057. foreach (to_array($this->id_def) as $id) {
  1058. if ($column_id != "") {
  1059. $column_id .= ",";
  1060. }
  1061. $column_id .= $this->my_db_ro->quoteIdentifier($this->_getPrimaryTable())
  1062. . "." . $this->my_db_ro->quoteIdentifier($id);
  1063. }
  1064. $condition = $this->_getSQL_SearchCondition($filter);
  1065. $sort = "";
  1066. if (is_array($order)) {
  1067. foreach ($order as $k => $v) {
  1068. if ($sort == "") {
  1069. $sort = "ORDER BY ";
  1070. } else {
  1071. $sort .= ", ";
  1072. }
  1073. $sort .= sprintf("%s %s", $this->my_db_ro->quoteIdentifier($k),
  1074. $v == OBJECT_SORT_ASC ? "ASC" : "DESC");
  1075. }
  1076. }
  1077. $limit = "";
  1078. if (is_null($count) == false) {
  1079. $limit = sprintf("LIMIT %d", $count);
  1080. if (is_null($offset) == false) {
  1081. $limit .= sprintf(" OFFSET %d", $offset);
  1082. }
  1083. }
  1084. $sql = "SELECT DISTINCT $column_id FROM $tables $condition $sort $limit";
  1085. return $sql;
  1086. }
  1087. // }}}
  1088. // {{{ _getSQL_SearchProp
  1089. /**
  1090. * ????????????????SQL??????
  1091. *
  1092. * @access private
  1093. * @param array $keys ???????(????)??
  1094. * @param array $filter WHERE????(???????????????????Ethna_AppSearchObject???)
  1095. * @param array $order ?????????
  1096. * (?????????????????? OBJECT_SORT_ASC, ???????OBJECT_SORT_DESC)
  1097. * @param int $offset ???????????
  1098. * @param int $count ???????
  1099. * @return string ???????????SELECT?
  1100. */
  1101. function _getSQL_SearchProp($keys, $filter, $order, $offset, $count)
  1102. {
  1103. // ????
  1104. $tables = implode(',',
  1105. $this->my_db_ro->quoteIdentifier(array_keys($this->table_def)));
  1106. if ($this->_isAdditionalField($filter)
  1107. || $this->_isAdditionalField($order)) {
  1108. $tables .= " " . $this->_SQLPlugin_SearchTable();
  1109. }
  1110. $p_table = $this->_getPrimaryTable();
  1111. // ??????????
  1112. // ??????????????????????
  1113. // ????????? _SQLPlugin_SearchPropDef ????
  1114. //
  1115. // ?????????????????????????
  1116. // ???(??. ?????)
  1117. if ($this->_isAdditionalField($filter)
  1118. || $this->_isAdditionalField($order)) {
  1119. $search_prop_def = $this->_SQLPlugin_SearchPropDef();
  1120. } else {
  1121. $search_prop_def = array();
  1122. }
  1123. $def = array_merge($this->getDef(), $search_prop_def);
  1124. // ???
  1125. $column = "";
  1126. $keys = $keys === null ? array_keys($def) : to_array($keys);
  1127. foreach ($keys as $key) {
  1128. if ($column != "") {
  1129. $column .= ", ";
  1130. }
  1131. $t = isset($def[$key]['table']) ? $def[$key]['table'] : $p_table;
  1132. // ?????.????
  1133. $column .= sprintf("%s.%s",
  1134. $this->my_db_ro->quoteIdentifier($t),
  1135. $this->my_db_ro->quoteIdentifier($key));
  1136. }
  1137. // WHERE ???
  1138. $condition = $this->_getSQL_SearchCondition($filter);
  1139. // ORDER BY
  1140. $sort = "";
  1141. if (is_array($order)) {
  1142. foreach ($order as $k => $v) {
  1143. if ($sort == "") {
  1144. $sort = "ORDER BY ";
  1145. } else {
  1146. $sort .= ", ";
  1147. }
  1148. $sort .= sprintf("%s %s",
  1149. $this->my_db_ro->quoteIdentifier($k),
  1150. $v == OBJECT_SORT_ASC ? "ASC" : "DESC");
  1151. }
  1152. }
  1153. // LIMIT, OFFSET
  1154. $limit = "";
  1155. if (is_null($count) == false) {
  1156. $limit = sprintf("LIMIT %d", $count);
  1157. if (is_null($offset) == false) {
  1158. $limit .= sprintf(" OFFSET %d", $offset);
  1159. }
  1160. }
  1161. $sql = "SELECT $column FROM $tables $condition $sort $limit";
  1162. return $sql;
  1163. }
  1164. // }}}
  1165. // {{{ _getSQL_SearchCondition
  1166. /**
  1167. * ????????SQL?????????
  1168. *
  1169. * @access private
  1170. * @param array $filter WHERE????(???????????????????Ethna_AppSearchObject???)
  1171. * @return string ????????????(?????null)
  1172. */
  1173. function _getSQL_SearchCondition($filter)
  1174. {
  1175. if (is_array($filter) == false) {
  1176. return "";
  1177. }
  1178. $p_table = $this->_getPrimaryTable();
  1179. // ??????????
  1180. // ??????????????????????
  1181. // ????????? _SQLPlugin_SearchPropDef ????
  1182. //
  1183. // ?????????????????????????
  1184. // ???(??. ?????)
  1185. if ($this->_isAdditionalField($filter)) {
  1186. $search_prop_def = $this->_SQLPlugin_SearchPropDef();
  1187. } else {
  1188. $search_prop_def = array();
  1189. }
  1190. $prop_def = array_merge($this->prop_def, $search_prop_def);
  1191. $condition = null;
  1192. foreach ($filter as $k => $v) {
  1193. if (isset($prop_def[$k]) == false) {
  1194. trigger_error(sprintf("Unknown property [%s]", $k), E_USER_ERROR);
  1195. return null;
  1196. }
  1197. if (is_null($condition)) {
  1198. $condition = "WHERE ";
  1199. } else {
  1200. $condition .= " AND ";
  1201. }
  1202. $t = isset($prop_def[$k]['table']) ? $prop_def[$k]['table'] : $p_table;
  1203. // ?????????????Ethna_AppSearchObject
  1204. // ???????? ??????? LIKE, ?????
  1205. // ? = ????????????????
  1206. if (is_object($v)) {
  1207. // Ethna_AppSearchObject??????????
  1208. $condition .= $v->toString(
  1209. $this->my_db_ro->quoteIdentifier($t)
  1210. .'.'. $this->my_db_ro->quoteIdentifier($k));
  1211. } else if (is_array($v) && count($v) > 0 && is_object($v[0])) {
  1212. // Ethna_AppSearchObject?????????????
  1213. $n = 0;
  1214. foreach ($v as $so) {
  1215. if ($n > 0) {
  1216. $condition .= " AND ";
  1217. }
  1218. $condition .= $so->toString(
  1219. $this->my_db_ro->quoteIdentifier($t)
  1220. .'.'. $this->my_db_ro->quoteIdentifier($k));
  1221. $n++;
  1222. }
  1223. } else if ($prop_def[$k]['type'] == VAR_TYPE_STRING) {
  1224. // ???(???)
  1225. Ethna_AppSQL::escapeSQL($v, $this->my_db_type);
  1226. $condition .= Ethna_AppSQL::getCondition(
  1227. $this->my_db_ro->quoteIdentifier($t)
  1228. .'.'. $this->my_db_ro->quoteIdentifier($k),
  1229. $v, OBJECT_CONDITION_LIKE);
  1230. } else {
  1231. // ???(??)
  1232. Ethna_AppSQL::escapeSQL($v, $this->my_db_type);
  1233. $condition .= Ethna_AppSQL::getCondition(
  1234. $this->my_db_ro->quoteIdentifier($t)
  1235. .'.'. $this->my_db_ro->quoteIdentifier($k),
  1236. $v, OBJECT_CONDITION_EQ);
  1237. }
  1238. }
  1239. return $condition;
  1240. }
  1241. // }}}
  1242. // {{{ _SQLPlugin_SearchTable
  1243. /**
  1244. * ????????SQL?????(??????)
  1245. *
  1246. * sample:
  1247. * <code>
  1248. * return " LEFT JOIN bar_tbl ON foo_tbl.user_id=bar_tbl.user_id";
  1249. * </code>
  1250. *
  1251. * @access protected
  1252. * @return string ????JOIN?SQL?
  1253. */
  1254. function _SQLPlugin_SearchTable()
  1255. {
  1256. return "";
  1257. }
  1258. // }}}
  1259. // {{{ _SQLPlugin_SearchPropDef
  1260. /**
  1261. * ????????SQL?????(??????)
  1262. *
  1263. * sample:
  1264. * <code>
  1265. * $search_prop_def = array(
  1266. * 'group_id' => array(
  1267. * 'primary' => true, 'key' => true, 'type' => VAR_TYPE_INT,
  1268. * 'form_name' => 'group_id', 'table' => 'group_user_tbl',
  1269. * ),
  1270. * );
  1271. * return $search_prop_def;
  1272. * </code>
  1273. *
  1274. * @access protected
  1275. * @return array ??????
  1276. */
  1277. function _SQLPlugin_SearchPropDef()
  1278. {
  1279. return array();
  1280. }
  1281. // }}}
  1282. // {{{ _dump_csv
  1283. /**
  1284. * ????????????CSV????????
  1285. *
  1286. * @access protected
  1287. * @return string ?????
  1288. */
  1289. function _dump_csv()
  1290. {
  1291. $dump = "";
  1292. $n = 0;
  1293. foreach ($this->getDef() as $k => $def) {
  1294. if ($n > 0) {
  1295. $dump .= ",";
  1296. }
  1297. $dump .= Ethna_Util::escapeCSV($this->getName($k));
  1298. $n++;
  1299. }
  1300. return $dump;
  1301. }
  1302. // }}}
  1303. // {{{ _isAdditionalField
  1304. /**
  1305. * (????|?????)????????????????
  1306. * ????????????????????
  1307. *
  1308. * @access private
  1309. * @param array $field (????|?????)??
  1310. * @return bool true:???? false:?????
  1311. */
  1312. function _isAdditionalField($field)
  1313. {
  1314. if (is_array($field) == false) {
  1315. return false;
  1316. }
  1317. $def = $this->getDef();
  1318. foreach ($field as $key => $value) {
  1319. if (array_key_exists($key, $def) == false) {
  1320. return true;
  1321. }
  1322. if (is_object($value)) {
  1323. // Ethna_AppSearchObject
  1324. if ($value->isTarget($key)) {
  1325. return true;
  1326. }
  1327. }
  1328. }
  1329. return false;
  1330. }
  1331. // }}}
  1332. // {{{ _clearPropCache
  1333. /**
  1334. * ?????????????
  1335. *
  1336. * @access private
  1337. */
  1338. function _clearPropCache()
  1339. {
  1340. $class_name = strtolower(get_class($this));
  1341. foreach (array('_ETHNA_APP_OBJECT_CACHE',
  1342. '_ETHNA_APP_MANAGER_OL_CACHE',
  1343. '_ETHNA_APP_MANAGER_OPL_CACHE',
  1344. '_ETHNA_APP_MANAGER_OP_CACHE') as $key) {
  1345. if (array_key_exists($key, $GLOBALS)
  1346. && array_key_exists($class_name, $GLOBALS[$key])) {
  1347. unset($GLOBALS[$key][$class_name]);
  1348. }
  1349. }
  1350. }
  1351. // }}}
  1352. // {{{ _getDBList
  1353. /**
  1354. * DB??????(read only/read-write)?????
  1355. *
  1356. * @access protected
  1357. * @return array array('ro' => {read only db object}, 'rw' => {read-write db object})
  1358. */
  1359. function _getDBList()
  1360. {
  1361. $r = array('ro' => null, 'rw' => null);
  1362. $db_list = $this->backend->getDBList();
  1363. if (Ethna::isError($db_list)) {
  1364. return $r;
  1365. }
  1366. foreach ($db_list as $elt) {
  1367. if ($this->db_prefix) {
  1368. // ???????????????DB?????
  1369. // (???????DB????????)
  1370. if (strncmp($this->db_prefix,
  1371. $elt['key'],
  1372. strlen($this->db_prefix)) != 0) {
  1373. continue;
  1374. }
  1375. }
  1376. $varname = $elt['varname'];
  1377. // for B.C.
  1378. $this->$varname = $elt['db'];
  1379. if ($elt['type'] == DB_TYPE_RW) {
  1380. $r['rw'] = $elt['db'];
  1381. } else if ($elt['type'] == DB_TYPE_RO) {
  1382. $r['ro'] = $elt['db'];
  1383. }
  1384. }
  1385. if ($r['ro'] == null && $r['rw'] != null) {
  1386. $r['ro'] = $r['rw'];
  1387. }
  1388. return $r;
  1389. }
  1390. // }}}
  1391. // {{{ _getTableDef
  1392. /**
  1393. * ???????????
  1394. *
  1395. * (??????????????????????
  1396. * ?????????????????)
  1397. *
  1398. * @access protected
  1399. * @return array ??????
  1400. */
  1401. function _getTableDef()
  1402. {
  1403. $class_name = get_class($this);
  1404. if (preg_match('/(\w+)_(.*)/', $class_name, $match) == 0) {
  1405. return null;
  1406. }
  1407. $table = $match[2];
  1408. // PHP 4?????????...??PHP 5??
  1409. $table = preg_replace('/^([A-Z])/e', "strtolower('\$1')", $table);
  1410. $table = preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $table);
  1411. // JOIN ??????????????????????
  1412. // ??????? primary ? true???
  1413. return array($table => array('primary' => true));
  1414. }
  1415. // }}}
  1416. // {{{ _getPropDef
  1417. /**
  1418. * ????????????????????????????
  1419. * ??????????
  1420. *
  1421. * @access protected
  1422. * @return array ???????
  1423. */
  1424. function _getPropDef()
  1425. {
  1426. if (is_null($this->table_def)) {
  1427. return null;
  1428. }
  1429. foreach ($this->table_def as $table_name => $table_attr) {
  1430. // use 1st one
  1431. break;
  1432. }
  1433. $cache_manager = Ethna_CacheManager::getInstance('localfile');
  1434. $cache_manager->setNamespace('ethna_app_object');
  1435. $cache_key = md5($this->my_db_ro->getDSN() . '-' . $table_name);
  1436. if ($cache_manager->isCached($cache_key, $this->prop_def_cache_lifetime)) {
  1437. $prop_def = $cache_manager->get($cache_key,
  1438. $this->prop_def_cache_lifetime);
  1439. if (Ethna::isError($prop_def) == false) {
  1440. return $prop_def;
  1441. }
  1442. }
  1443. $r = $this->my_db_ro->getMetaData($table_name);
  1444. if(Ethna::isError($r)){
  1445. return null;
  1446. }
  1447. $prop_def = array();
  1448. foreach ($r as $i => $field_def) {
  1449. $primary = in_array('primary_key', $field_def['flags']);
  1450. $seq = in_array('sequence', $field_def['flags']);
  1451. $required = in_array('not_null', $field_def['flags']);
  1452. $key = in_array('primary_key', $field_def['flags'])
  1453. || in_array('multiple_key', $field_def['flags'])
  1454. || in_array('unique_key', $field_def['flags']);
  1455. switch ($field_def['type']) {
  1456. case 'int':
  1457. $type = VAR_TYPE_INT;
  1458. break;
  1459. case 'boolean':
  1460. $type = VAR_TYPE_BOOLEAN;
  1461. break;
  1462. case 'datetime':
  1463. $type = VAR_TYPE_DATETIME;
  1464. break;
  1465. default:
  1466. $type = VAR_TYPE_STRING;
  1467. break;
  1468. }
  1469. $prop_def[$field_def['name']] = array(
  1470. 'primary' => $primary,
  1471. 'seq' => $seq,
  1472. 'key' => $key,
  1473. 'type' => $type,
  1474. 'required' => $required,
  1475. 'length' => $field_def['len'],
  1476. 'form_name' => $this->_fieldNameToFormName($field_def),
  1477. 'table' => $table_name,
  1478. );
  1479. }
  1480. $cache_manager->set($cache_key, $prop_def);
  1481. return $prop_def;
  1482. }
  1483. // }}}
  1484. // {{{ _fieldNameToFormName
  1485. /**
  1486. * ???????????????????????????
  1487. *
  1488. * @access protected
  1489. */
  1490. function _fieldNameToFormName($field_def)
  1491. {
  1492. return $field_def['name'];
  1493. }
  1494. // }}}
  1495. }
  1496. // }}}