PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/Model/model.php

https://github.com/jplante815/meican
PHP | 658 lines | 383 code | 81 blank | 194 comment | 89 complexity | 1f4d19962417597ef5a85e8c0b56811c MD5 | raw file
  1. <?php
  2. include_once 'libs/Model/attribute.php';
  3. //include_once 'libs/acl_loader.php';
  4. App::uses('ConnectionManager', 'Model');
  5. class Model extends Object {
  6. public $attributes;
  7. private $tableName;
  8. private $databaseString;
  9. public $configName = 'default';
  10. function Model() {
  11. $this->attributes = array();
  12. }
  13. public function getDatabaseString() {
  14. return $this->databaseString;
  15. }
  16. public function setDatabaseString($string) {
  17. $this->databaseString = $string;
  18. return true;
  19. }
  20. public function setAccessTableName($tableName) {
  21. $this->accessTableName = $tableName;
  22. return true;
  23. }
  24. protected function addAttribute($name, $type, $primaryKey=false, $usedInInsert=true, $usedInUpdate=true, $forceUpdate=false) {
  25. $this->attributes[$name] = new Attribute($name, $type, $primaryKey, $usedInInsert, $usedInUpdate, $forceUpdate);
  26. $this->$name = "";
  27. }
  28. public function setTableName($n) {
  29. $this->tableName = $n;
  30. }
  31. public function getTableName() {
  32. if ($this->tableName == "") {
  33. return get_class($this);
  34. }
  35. return $this->tableName;
  36. }
  37. public function getPrimaryKey() {
  38. $primaryKey = NULL;
  39. foreach ($this->attributes as $attribute) {
  40. if ($attribute->primaryKey) {
  41. $primaryKey = $attribute->name;
  42. break;
  43. }
  44. }
  45. return $primaryKey;
  46. }
  47. public function getValidInds() {
  48. return (Common::arrayExtractAttr($this->attributes, "name"));
  49. }
  50. /**
  51. *
  52. * @param <type> $options
  53. * @return <boolean> FALSE: no object found
  54. * @return <array> Object Model: objects were found
  55. */
  56. public function fetch($useACL = true) {
  57. $tableName = $this->getTableName();
  58. $whereArgsString = $this->buildWhere();
  59. $sql = "";
  60. if ($useACL) {
  61. include_once 'libs/acl_loader.php';
  62. $acl = AclLoader::getInstance();
  63. $allowPks = $acl->getAllowedPKey('read', $tableName);
  64. if ($allowPks) {
  65. $inString = implode(', ', $allowPks);
  66. $pk = $this->getPrimaryKey();
  67. if ($whereArgsString)
  68. $sql = "SELECT * FROM `$tableName` WHERE $whereArgsString AND `$pk` IN ($inString)";
  69. else
  70. $sql = "SELECT * FROM `$tableName` WHERE `$pk` IN ($inString)";
  71. } else {
  72. $empty = array();
  73. return $empty; //sem acesso a nada
  74. }
  75. } else { //sem ACL
  76. if ($whereArgsString)
  77. $sql = "SELECT * FROM `$tableName` WHERE $whereArgsString";
  78. else
  79. $sql = "SELECT * FROM `$tableName`";
  80. }
  81. //debug("fetch",$sql);
  82. //Log::write('debug',"sql fetch:\n" . print_r($sql,true));
  83. return ($this->data = $this->querySql($sql, $tableName));
  84. }
  85. /**
  86. * @example Before calling this function, all the 'usedInUpdate' attributes must be set, even when it should be NULL.
  87. * Otherwise, the param will be set blank
  88. * @return Boolean TRUE if update was success, FALSE otherwise
  89. */
  90. public function update() {
  91. $pk = $this->getPrimaryKey();
  92. if (!$this->{$pk})
  93. return FALSE;
  94. $classname = $this->getTableName();
  95. $values = get_object_vars($this);
  96. $sql = "UPDATE `$classname` SET ";
  97. $isFirst = true;
  98. foreach ($this->attributes as $attribute) {
  99. $name = $attribute->name;
  100. if (($attribute->type == "VARCHAR") && ($values[$name] !== NULL)) {
  101. $values[$name] = "'" . $values[$name] . "'";
  102. }
  103. if ($attribute->usedInUpdate) {
  104. if ($isFirst) {
  105. $isFirst = false;
  106. } else {
  107. $sql.=", ";
  108. }
  109. if ($values[$name] === NULL)
  110. $sql .= "`$name`=NULL";
  111. else
  112. $sql .= "`$name`=" . $values[$name];
  113. }
  114. }
  115. $where = " WHERE `$pk`=" . $this->{$pk};
  116. $sql .= $where;
  117. //debug('update',$sql);
  118. return $this->execSql($sql);
  119. }
  120. /**
  121. * @deprecated OBSOLET FUNCTION -> replaced by update()
  122. *
  123. */
  124. /**
  125. * Utiliza a PRIMARY_KEY do modelo para selecionar a linha a ser alterada.
  126. * Esse atributo precisa estar setado.
  127. * Os demais atributos que estiverem setados serão alterados. Os atributos que não estiverem setados
  128. * serão mantidos.
  129. *
  130. * @return <boolean> TRUE if update was success, FALSE otherwise
  131. */
  132. /*
  133. public function update2() {
  134. //algoritmo simplificado:
  135. //achar a chave primária
  136. //fazer um fetch com o valor da chave primária setado no controller
  137. //alterar SOMENTE os atributos que foram setados no controller e deixar os demais inalterados
  138. // inicia objeto temporário para manter as informações do objeto original
  139. $validInd = array();
  140. // varre a estrutura em busca da chave primária e constrói um vetor com índices válidos
  141. foreach ($this->attributes as $attribute) {
  142. if ($attribute->primaryKey)
  143. $primaryKey[] = $attribute->name;
  144. $validInd[] = $attribute->name;
  145. }
  146. // copia a chave primária (será usada na busca da linha a ser alterada no banco)
  147. //return "ERROR: database_object.inc -> UPDATE : PRIMARY KEY $primaryKey NÃO SETADA.";
  148. $fetchObj = new $this->tableName;
  149. foreach ($primaryKey as $pk) {
  150. if (!$this->$pk) {
  151. debug('set all the primary keys to update.', $pk);
  152. return FALSE;
  153. }
  154. else
  155. $fetchObj->$pk = $this->$pk;
  156. }
  157. $result = $fetchObj->fetch(FALSE);
  158. $fetchResult = $result[0];
  159. $changed = FALSE;
  160. if ($fetchResult !== FALSE) {
  161. // varre os atributos do objeto original, verifica se não está setado
  162. foreach ($this as $name => $val) {
  163. if (array_search($name, $validInd) !== FALSE) { //verifica se o índice selecionado do objeto é um índice válido
  164. if ($val) { //se atributo do modelo estiver setado
  165. if (($val != $fetchResult->$name) || ($this->attributes[$name]->forceUpdate)) //testa se o valor é diferente OU é um atributo que SEMPRE deve ser alterado
  166. $changed = TRUE;
  167. } else {
  168. // copia o resultado da busca feita sobre o objeto temporário para o objeto original (os valores que não serão alterados)
  169. $this->$name = $fetchResult->$name;
  170. }
  171. }
  172. }
  173. } else
  174. return FALSE;
  175. /** @todo : log
  176. //return "ERROR: database_object.inc -> UPDATE : PRIMARY KEY $primaryKey NÃO ENCONTRADA.";
  177. *
  178. *
  179. if (!$changed) {
  180. debug("not updated");
  181. return FALSE;
  182. }
  183. if (sizeof($this->attributes) == 0)
  184. //return "Atributos invalidos";
  185. return FALSE;
  186. $classname = $this->getTableName();
  187. $values = get_object_vars($this);
  188. $sql = "UPDATE `$classname` SET ";
  189. $isFirst = true;
  190. $isFirstWhere = true;
  191. $where = " WHERE ";
  192. foreach ($this->attributes as $attribute) {
  193. $name = $attribute->name;
  194. if (($attribute->type == "VARCHAR") && ($values[$name] !== NULL)) {
  195. $values[$name] = "'" . $values[$name] . "'";
  196. }
  197. if ($attribute->usedInUpdate) {
  198. if ($isFirst) {
  199. $isFirst = false;
  200. } else {
  201. $sql.=", ";
  202. }
  203. if ($values[$name] === NULL)
  204. $sql .= "`$name`=NULL";
  205. else
  206. $sql .= "`$name`=" . $values[$name];
  207. }
  208. if ($attribute->primaryKey) {
  209. if ($isFirstWhere) {
  210. $isFirstWhere = false;
  211. } else {
  212. $where .= " AND ";
  213. }
  214. $where .= "`$name`=" . $values[$name];
  215. }
  216. }
  217. $sql .= $where;
  218. //debug('update',$sql);
  219. return $this->execSql($sql);
  220. }
  221. */
  222. /**
  223. *
  224. * @param Array $alt An array containing only the attributes to update
  225. * @param Boolean $useACL Whether to use ACL or not, default is TRUE
  226. * @return Boolean TRUE if operation was successful, FALSE otherwise
  227. * @example This function is better to use when only some attributes of the model are updated, and not all of them
  228. */
  229. public function updateTo($alt = Array(), $useACL = TRUE) {
  230. if (!$alt)
  231. return FALSE;
  232. $tableName = $this->getTableName();
  233. $values = get_object_vars($this);
  234. $validInds = $this->getValidInds();
  235. $setArgs = array();
  236. foreach ($alt as $ind => $val) {
  237. if (array_search($ind, $validInds) !== FALSE) { //indice valido
  238. if ($val === NULL) {
  239. $setArgs[] = "`$ind`=NULL";
  240. } else {
  241. if ($this->attributes[$ind]->type == "VARCHAR")
  242. $alt[$ind] = "\"" . $alt[$ind] . "\"";
  243. $setArgs[] = "`$ind`=$alt[$ind]";
  244. }
  245. }
  246. }
  247. if (isset($setArgs))
  248. $setArgsString = implode(',', $setArgs);
  249. else
  250. return FALSE;
  251. if (!$setArgsString)
  252. return FALSE;
  253. $whereArgsString = $this->buildWhere();
  254. $sql = "";
  255. $sqlfetch = "";
  256. if ($useACL) {
  257. include_once 'libs/acl_loader.php';
  258. $acl = AclLoader::getInstance();
  259. $allowPks = $acl->getAllowedPKey('update', $tableName);
  260. if ($allowPks) {
  261. $inString = implode(',', $allowPks);
  262. $pk = $this->getPrimaryKey();
  263. if ($whereArgsString) {
  264. $sql = "UPDATE `$tableName` SET $setArgsString WHERE $whereArgsString AND `$pk` IN ($inString)";
  265. $sqlfetch = "SELECT * FROM `$tableName` WHERE $whereArgsString AND `$pk` IN ($inString)";
  266. } else {
  267. $sql = "UPDATE `$tableName` WHERE `$pk` IN ($inString)";
  268. $sqlfetch = "SELECT * FROM `$tableName` WHERE `$pk` IN ($inString)";
  269. }
  270. } else
  271. return FALSE; //sem acesso a nada
  272. } else { //sem ACL
  273. if ($whereArgsString) {
  274. $sql = "UPDATE `$tableName` SET $setArgsString WHERE $whereArgsString";
  275. $sqlfetch = "SELECT * FROM `$tableName` WHERE $whereArgsString";
  276. }
  277. else
  278. $sql = "UPDATE `$tableName` SET $setArgsString";
  279. }
  280. $resfetch = $this->querySql($sqlfetch, $tableName);
  281. //debug('sql update', $sql);
  282. //Log::write('debug',"sql update:\n" . print_r($sql,true));
  283. if (!$resfetch)
  284. return FALSE;
  285. else
  286. return $this->execSql($sql);
  287. }
  288. //do updateTo
  289. /**
  290. * @return Boolean FALSE : on failed insertion (FAILED)
  291. * @return Class Object : the inserted object if it was possible to find it (SUCCESS)
  292. * @return Boolean TRUE : the object was inserted, but it was not possible to find it (SUCCESS)
  293. */
  294. public function insert() {
  295. $classname = $this->getTableName();
  296. $values = get_object_vars($this);
  297. $isFirst = true;
  298. $sqlNames = "";
  299. $sqlValues = "";
  300. foreach ($this->attributes as $attribute) {
  301. if ($attribute->usedInInsert) {
  302. $name = $attribute->name;
  303. if ($isFirst) {
  304. $isFirst = false;
  305. } else {
  306. $sqlValues.=", ";
  307. $sqlNames.=", ";
  308. }
  309. $sqlNames .= "`$name`";
  310. if ($values[$name] === NULL)
  311. $sqlValues .= "NULL";
  312. else {
  313. if ($attribute->type == "VARCHAR")
  314. $sqlValues .= "'" . $values[$name] . "'";
  315. else
  316. $sqlValues .= $values[$name];
  317. }
  318. }
  319. }
  320. $sql = "INSERT INTO `$classname` ($sqlNames) values ($sqlValues)";
  321. //Log::write('debug', "SQL insert:\n" . print_r($sql, true));
  322. $id = $this->insertSql($sql);
  323. if ($id !== FALSE) {
  324. // se ID não for idêntico a FALSE, é porque foi inserido
  325. // agora TENTA buscar objeto inserido para retornar
  326. $pk = $this->getPrimaryKey();
  327. if ($id && $pk) {
  328. // se retornou um ID válido, busca por ele como PK
  329. $object = new $classname;
  330. $object->$pk = $id;
  331. if ($ret = $object->fetch(FALSE))
  332. return $ret[0];
  333. } else {
  334. // se não retornou ID válido, busca pelos atributos utilizados na inserção
  335. if ($ret = $this->fetch(FALSE))
  336. return $ret[0];
  337. }
  338. // se não conseguiu buscar objeto, apenas retorna TRUE
  339. Log::write('warning', "Object inserted but not found");
  340. return TRUE;
  341. } else {
  342. // objeto não inserido, retorna FALSE
  343. Log::write('error', "Error to execute insert SQL:\n" . print_r($sql, TRUE));
  344. return FALSE;
  345. }
  346. }
  347. /**
  348. *
  349. * @return Boolean TRUE if delete was success, FALSE otherwise
  350. */
  351. public function delete($useACL = TRUE) {
  352. $tableName = $this->getTableName();
  353. $pk = $this->getPrimaryKey();
  354. $fetch = $this->fetch(FALSE);
  355. if (!$fetch)
  356. return FALSE;
  357. $toDelete = array();
  358. foreach ($fetch as $f) { //retorna todas as chaves primarias para deletar
  359. $toDelete[] = $f->{$pk};
  360. }
  361. //debug('todelete', $toDelete);
  362. if (!$toDelete) {
  363. return FALSE;
  364. }
  365. $values = get_object_vars($this);
  366. $whereArgs = array();
  367. if ($useACL) {
  368. include_once 'libs/acl_loader.php';
  369. $acl = AclLoader::getInstance();
  370. $restr = $acl->getAllowedPKey('delete', $tableName);
  371. //delete nao permite where do tipo IN
  372. foreach ($toDelete as $d) {
  373. if (array_search($d, $restr) !== FALSE) { //verifica se a chave q quer deletar está dentro das permissoes
  374. if ($this->attributes[$pk]->type == "VARCHAR")
  375. $whereArgs[] = "`$pk`='$d'";
  376. else
  377. $whereArgs[] = "`$pk`=$d";
  378. }
  379. }
  380. } else {
  381. foreach ($toDelete as $d) {
  382. if ($this->attributes[$pk]->type == "VARCHAR")
  383. $whereArgs[] = "`$pk`='$d'";
  384. else
  385. $whereArgs[] = "`$pk`=$d";
  386. }
  387. }
  388. $sql = NULL;
  389. if ($whereArgs) {
  390. $whereArgsString = implode(' OR ', $whereArgs);
  391. $sql = "DELETE FROM `$tableName` WHERE $whereArgsString";
  392. //fetch before update to return false if none results will be selected
  393. $sqlfetch = "SELECT * FROM `$tableName` WHERE $whereArgsString";
  394. $result = $this->querySql($sqlfetch, $tableName);
  395. if (!$result) //nao consigurira atualizar nada
  396. return FALSE;
  397. }
  398. return $this->execSql($sql);
  399. }
  400. public function getDataSource(){
  401. $config = Configure::read('useDatabase');
  402. if (!$config) $config = 'default';
  403. return ConnectionManager::getDataSource($config);
  404. }
  405. /**
  406. *
  407. * @param String $sql : well-formatted SQL string
  408. * @return Boolean Object ID if insert was successful, FALSE otherwise
  409. */
  410. protected function insertSql($sql) {
  411. $ds = $this->getDataSource();
  412. if (!($ds && $sql))
  413. return FALSE;
  414. if ($ds->execute($sql))
  415. return $ds->lastInsertId();
  416. else
  417. return false;
  418. }
  419. /**
  420. *
  421. * @param String $sql well-formatted SQL string
  422. * @return Boolean TRUE if exec was successful, FALSE otherwise
  423. */
  424. protected function execSql($sql) {
  425. $ds = $this->getDataSource();
  426. if (!($ds && $sql))
  427. return FALSE;
  428. $ret = $ds->execute($sql);
  429. $ds->flushQueryCache();
  430. return $ret;
  431. }
  432. /**
  433. *
  434. * @param <string> $sql : SQL string using ';' as separator for the 'explode()' function.
  435. * Ex: "DELETE FROM $tableName WHERE lft BETWEEN $left AND $right;
  436. * UPDATE $tableName SET rgt = rgt - $width WHERE rgt > $right;
  437. * UPDATE $tableName SET lft = lft - $width WHERE lft > $right;"
  438. *
  439. * @return <boolean> TRUE if transaction was successful. FALSE otherwise.
  440. */
  441. protected function transactionSql($sql) {
  442. $ds = $this->getDataSource();
  443. if (!($ds && $sql))
  444. return FALSE;
  445. $ds->begin();
  446. if (!$ds->execute($sql))
  447. return $ds->rollback() && false;
  448. else
  449. return $ds->commit();
  450. }
  451. /**
  452. *
  453. * @param <string> $sql well-formatted SQL string
  454. * @param <string> $tableName : name of class or table model
  455. * @return <boolean> FALSE: no object found
  456. * @return <array> Object Model: objects were found
  457. */
  458. protected function querySql($sql, $tableName = 'Model') {
  459. $ds = self::getDataSource();
  460. if (!($ds && $sql))
  461. return FALSE;
  462. $results = $ds->fetchAll($sql);
  463. if (empty($results))
  464. return array();/*
  465. if (!in_array($tableName, array('acos', 'aros', 'domain_info', 'reservation_info')))
  466. $tableName = 'stdClass';*/
  467. $result_obj = array();
  468. foreach ($results as &$row) {
  469. $obj = new $tableName();
  470. foreach ($row as $model => $modelRow)
  471. foreach ($modelRow as $key => $value) {
  472. $obj->$key = $value;
  473. }
  474. $result_obj[] = $obj;
  475. }
  476. return $result_obj;
  477. /* if ($db->query($sql, $tableName)) {
  478. $result_obj = array();
  479. while ($db->hasNext()) {
  480. $result_obj[] = $db->next();
  481. }
  482. debug($result_obj);
  483. return $result_obj;
  484. } else {
  485. return FALSE;
  486. } */
  487. }
  488. private function normalizeStringArray($data = array()) {
  489. foreach ($data as &$item)
  490. $item = '"' . $item . '"';
  491. return $data;
  492. }
  493. function buildWhere($fields=array()) {
  494. $values = get_object_vars($this);
  495. $validInds = $this->getValidInds();
  496. if (!$validInds)
  497. return FALSE;
  498. $newValidInds = array();
  499. if ($fields) {
  500. foreach ($validInds as $vi) {
  501. if (array_search($vi, $fields) !== FALSE) {
  502. $newValidInds[] = $vi;
  503. }
  504. }
  505. } else
  506. $newValidInds = $validInds;
  507. $whereArgs = array();
  508. foreach ($newValidInds as $vi) {
  509. if ($values[$vi] === NULL) {
  510. $whereArgs[] = "`$vi` IS NULL";
  511. } elseif ($values[$vi]) {
  512. if (is_array($values[$vi])) {
  513. if ($this->attributes[$vi]->type == "VARCHAR")
  514. $values[$vi] = $this->normalizeStringArray($values[$vi]);
  515. $whereArgs[] = "`$vi` IN (" . implode(', ', $values[$vi]) . ")";
  516. } else {
  517. if ($this->attributes[$vi]->type == "VARCHAR")
  518. $values[$vi] = "\"" . $values[$vi] . "\"";
  519. $whereArgs[] = "`$vi`=$values[$vi]";
  520. }
  521. }
  522. }
  523. if ($whereArgs)
  524. return implode(' AND ', $whereArgs);
  525. else
  526. return FALSE;
  527. }
  528. function getNextId($field) {
  529. $tableName = $this->getTableName();
  530. $whereString = $this->buildWhere();
  531. if ($whereString)
  532. $sql = "SELECT MAX(`$field`) as `$field` from `$tableName` WHERE $whereString";
  533. else
  534. $sql = "SELECT MAX(`$field`) as `$field` from `$tableName`";
  535. $result = $this->querySql($sql, $tableName);
  536. if ($result) {
  537. $last = $result[0]->{$field};
  538. return $last + 1;
  539. }
  540. return FALSE;
  541. }
  542. public function get($field=NULL, $useACL=TRUE) {
  543. if ($tmp = $this->fetch($useACL)) {
  544. if ($field)
  545. return $tmp[0]->{$field};
  546. else
  547. return $tmp[0];
  548. } else
  549. return FALSE;
  550. }
  551. public function fetchList() {
  552. if ($res = $this->fetch()) {
  553. $item = $res[0];
  554. $attr = $item->getValidInds();
  555. $temp = array();
  556. if (!empty($this->displayField)) {
  557. $temp[] = $item->{$this->displayField};
  558. } else
  559. foreach ($attr as $at_name) {
  560. if (($item->attributes[$at_name]->usedInInsert) && !($item->attributes[$at_name]->forceUpdate))
  561. $temp[] = "$at_name: " . $item->$at_name;
  562. }
  563. return implode("; ", $temp);
  564. }
  565. return false;
  566. }
  567. }