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

/tiendasikah/core/libs/db/active_record_base/active_record_base.php

http://tiendasikah.googlecode.com/
PHP | 1952 lines | 1351 code | 18 blank | 583 comment | 495 complexity | 900e4df9b7945bbeef229dece5157cb8 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * KumbiaPHP web & app Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://wiki.kumbiaphp.com/Licencia
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@kumbiaphp.com so we can send you a copy immediately.
  14. *
  15. * ActiveRecordBase Clase para el Mapeo Objeto Relacional
  16. *
  17. * @category Kumbia
  18. * @package Db
  19. * @subpackage ActiveRecord
  20. * @copyright Copyright (c) 2005-2009 Kumbia Team (http://www.kumbiaphp.com)
  21. * @license http://wiki.kumbiaphp.com/Licencia New BSD License
  22. */
  23. /**
  24. * ActiveRecordException
  25. */
  26. require_once CORE_PATH . 'libs/db/active_record_base/exception.php';
  27. /**
  28. * ActiveRecordBase Clase para el Mapeo Objeto Relacional
  29. *
  30. * Active Record es un enfoque al problema de acceder a los datos de una
  31. * base de datos en forma orientada a objetos. Una fila en la
  32. * tabla de la base de datos (o vista) se envuelve en una clase,
  33. * de manera que se asocian filas &uacute;nicas de la base de datos
  34. * con objetos del lenguaje de programaci&oacute;n usado.
  35. * Cuando se crea uno de estos objetos, se a&ntilde;de una fila a
  36. * la tabla de la base de datos. Cuando se modifican los atributos del
  37. * objeto, se actualiza la fila de la base de datos.
  38. *
  39. * Propiedades Soportadas:
  40. * $db = Conexion al Motor de Base de datos
  41. * $database = Base de datos a la que se conecta, especificada en databases.ini
  42. * $source = Tabla que contiene la tabla que esta siendo mapeada
  43. * $fields = Listado de Campos de la tabla que han sido mapeados
  44. * $count = Conteo del ultimo Resultado de un Select
  45. * $primary_key = Listado de columnas que conforman la llave primaria
  46. * $non_primary = Listado de columnas que no son llave primaria
  47. * $not_null = Listado de campos que son not_null
  48. * $attributes_names = nombres de todos los campos que han sido mapeados
  49. * $debug = Indica si se deben mostrar los SQL enviados al RDBM en pantalla
  50. * $logger = Si es diferente de false crea un log utilizando la clase Logger
  51. * en library/kumbia/logger/logger.php, esta crea un archivo .txt en logs/ con todas las
  52. * operaciones realizadas en ActiveRecord, si $logger = "nombre", crea un
  53. * archivo con ese nombre
  54. *
  55. * Propiedades sin Soportar:
  56. * $dynamic_update : La idea es que en un futuro ActiveRecord solo
  57. * actualize los campos que han cambiado. (En Desarrollo)
  58. * $dynamic_insert : Indica si los valores del insert son solo aquellos
  59. * que sean no nulos. (En Desarrollo)
  60. * $select_before_update: Exige realizar una sentencia SELECT anterior
  61. * a la actualizacion UPDATE para comprobar que los datos no hayan sido
  62. * cambiados (En Desarrollo)
  63. * $subselect : Permitira crear una entidad ActiveRecord de solo lectura que
  64. * mapearia los resultados de un select directamente a un Objeto (En Desarrollo)
  65. *
  66. */
  67. class ActiveRecordBase
  68. {
  69. //Soportados
  70. /**
  71. * Resource de conexion a la base de datos
  72. *
  73. * @var DbBase
  74. */
  75. public $db;
  76. /**
  77. * Base de datos a la que se conecta
  78. *
  79. * @var string
  80. */
  81. protected $database;
  82. /**
  83. * Schema donde esta la tabla
  84. *
  85. * @var string
  86. */
  87. protected $schema;
  88. /**
  89. * Tabla utilizada para realizar el mapeo
  90. *
  91. * @var string
  92. */
  93. protected $source;
  94. /**
  95. * Numero de resultados generados en la ultima consulta
  96. *
  97. * @var integer
  98. */
  99. public $count;
  100. /**
  101. * Nombres de los atributos de la entidad
  102. *
  103. * @var array
  104. */
  105. public $fields = array();
  106. /**
  107. * LLaves primarias de la entidad
  108. *
  109. * @var array
  110. */
  111. public $primary_key = array();
  112. /**
  113. * Campos que no son llave primaria
  114. *
  115. * @var array
  116. */
  117. public $non_primary = array();
  118. /**
  119. * Campos que no permiten nulos
  120. *
  121. * @var array
  122. */
  123. public $not_null = array();
  124. /**
  125. * Campos que tienen valor por defecto
  126. *
  127. * @var array
  128. */
  129. protected $_with_default = array();
  130. /**
  131. * Nombres de atributos, es lo mismo que fields
  132. *
  133. * @var array
  134. */
  135. public $attributes_names = array();
  136. /**
  137. * Indica si la clase corresponde a un mapeo de una vista
  138. * en la base de datos
  139. *
  140. * @var boolean
  141. */
  142. public $is_view = false;
  143. /**
  144. * Indica si el modelo esta en modo debug
  145. *
  146. * @var boolean
  147. */
  148. public $debug = false;
  149. /**
  150. * Indica si se logearan los mensajes generados por la clase
  151. *
  152. * @var mixed
  153. */
  154. public $logger = false;
  155. /**
  156. * Indica si los datos del modelo deben ser persistidos
  157. *
  158. * @var boolean
  159. */
  160. public $persistent = false;
  161. /**
  162. * Validaciones
  163. *
  164. * inclusion_in: el campo pertenece a un conjunto de elementos
  165. * exclusion_of: el campo no pertenece a un conjunto de elementos
  166. * numericality_of: el campo debe ser numerico
  167. * format_of: el campo debe coincidir con la expresion regular compatible con perl
  168. * date_in: el campo debe ser una fecha valida
  169. * email_in: el campo debe ser un correo electronico
  170. * uniqueness_of: el campo debe ser unico
  171. *
  172. * @var array
  173. **/
  174. protected $_validates = array('inclusion_in' => array(), 'exclusion_of' => array(), 'numericality_of' => array(),
  175. 'format_of' => array(), 'date_in' => array(), 'email_in' => array(), 'uniqueness_of' => array());
  176. /**
  177. * Campos que terminan en _in
  178. *
  179. * @var array
  180. */
  181. protected $_in = array();
  182. /**
  183. * Campos que terminan en _at
  184. *
  185. * @var array
  186. */
  187. protected $_at = array();
  188. /**
  189. * Variable para crear una condicion basada en los
  190. * valores del where
  191. *
  192. * @var string
  193. */
  194. protected $_where_pk;
  195. /**
  196. * Indica si ya se han obtenido los metadatos del Modelo
  197. *
  198. * @var boolean
  199. */
  200. protected $_dumped = false;
  201. /**
  202. * Indica si hay bloqueo sobre los warnings cuando una propiedad
  203. * del modelo no esta definida-
  204. *
  205. * @var boolean
  206. */
  207. protected $_dump_lock = false;
  208. /**
  209. * Tipos de datos de los campos del modelo
  210. *
  211. * @var array
  212. */
  213. protected $_data_type = array();
  214. /**
  215. * Relaciones a las cuales tiene una cardinalidad 1-1
  216. *
  217. * @var array
  218. */
  219. protected $_has_one = array();
  220. /**
  221. * Relaciones a las cuales tiene una cardinalidad 1-n
  222. *
  223. * @var array
  224. */
  225. protected $_has_many = array();
  226. /**
  227. * Relaciones a las cuales tiene una cardinalidad 1-1
  228. *
  229. * @var array
  230. */
  231. protected $_belongs_to = array();
  232. /**
  233. * Relaciones a las cuales tiene una cardinalidad n-n (muchos a muchos) o 1-n inversa
  234. *
  235. * @var array
  236. */
  237. protected $_has_and_belongs_to_many = array();
  238. /**
  239. * Clases de las cuales es padre la clase actual
  240. *
  241. * @var array
  242. */
  243. public $parent_of = array();
  244. /**
  245. * Persistance Models Meta-data
  246. */
  247. protected static $_models = array();
  248. /**
  249. * Persistance Models Meta-data
  250. */
  251. public static $models = array();
  252. /**
  253. * Constructor del Modelo
  254. *
  255. * @param array $data
  256. */
  257. function __construct($data=null)
  258. {
  259. if (!$this->source) {
  260. $this->_model_name();
  261. }
  262. /**
  263. * Inicializa el modelo en caso de que exista initialize
  264. */
  265. if (method_exists($this, 'initialize')) {
  266. $this->initialize();
  267. }
  268. /**
  269. * Conecta a la bd
  270. **/
  271. $this->_connect();
  272. if ($data) {
  273. if (!is_array($data))
  274. $data = Util::getParams(func_get_args());
  275. $this->dump_result_self($data);
  276. }
  277. }
  278. /**
  279. * Obtiene el nombre de la relacion en el RDBM a partir del nombre de la clase
  280. *
  281. */
  282. protected function _model_name()
  283. {
  284. if (!$this->source) {
  285. $this->source = Util::uncamelize(get_class($this));
  286. }
  287. }
  288. /**
  289. * Establece publicamente el $source de la tabla
  290. *
  291. * @param string $source
  292. */
  293. public function set_source($source)
  294. {
  295. $this->source = $source;
  296. }
  297. /**
  298. * Devuelve el source actual
  299. *
  300. * @return string
  301. */
  302. public function get_source()
  303. {
  304. return $this->source;
  305. }
  306. /**
  307. * Establece la base datos a utilizar
  308. *
  309. * @param string $databse
  310. */
  311. public function set_database($database)
  312. {
  313. $this->database = $database;
  314. }
  315. /**
  316. * Devuelve la base de datos
  317. *
  318. * @return string
  319. */
  320. public function get_database()
  321. {
  322. if ($this->database) {
  323. return $this->database;
  324. } else {
  325. $core = Config::read('config');
  326. return $core['application']['database'];
  327. }
  328. }
  329. /**
  330. * Pregunta si el ActiveRecord ya ha consultado la informacion de metadatos
  331. * de la base de datos o del registro persistente
  332. *
  333. * @return boolean
  334. */
  335. public function is_dumped()
  336. {
  337. return $this->_dumped;
  338. }
  339. /**
  340. * Valida que los valores que sean leidos del objeto ActiveRecord esten definidos
  341. * previamente o sean atributos de la entidad
  342. *
  343. * @param string $property
  344. */
  345. function __get($property)
  346. {
  347. if (!$this->_dump_lock) {
  348. if (!isset($this->$property)) {
  349. if (array_key_exists($property, $this->_belongs_to)) {
  350. $relation = $this->_belongs_to[$property];
  351. return self::get($relation->model)->find_first($this->{$relation->fk});
  352. } elseif (array_key_exists($property, $this->_has_one)) {
  353. $relation = $this->_has_one[$property];
  354. if ($this->{$this->primary_key[0]}) {
  355. return self::get($relation->model)->find_first("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
  356. } else {
  357. return null;
  358. }
  359. } elseif (array_key_exists($property, $this->_has_many)) {
  360. $relation = $this->_has_many[$property];
  361. if ($this->{$this->primary_key[0]}) {
  362. return self::get($relation->model)->find("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
  363. } else {
  364. return array();
  365. }
  366. } elseif (array_key_exists($property, $this->_has_and_belongs_to_many)) {
  367. $relation = $this->_has_and_belongs_to_many[$property];
  368. $relation_model = self::get($relation->model);
  369. $relation_model->dump_model();
  370. $source = $this->source;
  371. $relation_source = $relation_model->source;
  372. /**
  373. * Cargo atraves de que tabla se efectuara la relacion
  374. *
  375. */
  376. if (!isset($relation->through)) {
  377. if ($source > $relation_source) {
  378. $relation->through = "{$this->source}_{$relation_source}";
  379. } else {
  380. $relation->through = "{$relation_source}_{$this->source}";
  381. }
  382. }
  383. if ($this->{$this->primary_key[0]}) {
  384. return self::get($relation->model)->find_all_by_sql("SELECT $relation_source.* FROM $relation_source, {$relation->through}, $source
  385. WHERE {$relation->through}.{$relation->key} = {$this->db->add_quotes($this->{$this->primary_key[0]}) }
  386. AND {$relation->through}.{$relation->fk} = $relation_source.{$relation_model->primary_key[0]}
  387. AND {$relation->through}.{$relation->key} = $source.{$this->primary_key[0]}
  388. ORDER BY $relation_source.{$relation_model->primary_key[0]}");
  389. } else {
  390. return array();
  391. }
  392. } else {
  393. return null;
  394. }
  395. }
  396. }
  397. return $this->$property;
  398. }
  399. /**
  400. * Valida que los valores que sean asignados al objeto ActiveRecord esten definidos
  401. * o sean atributos de la entidad
  402. *
  403. * @param string $property
  404. * @param mixed $value
  405. */
  406. function __set($property, $value)
  407. {
  408. if (!$this->_dump_lock) {
  409. if (!isset($this->$property) && is_object($value) && is_subclass_of($value, 'ActiveRecordBase')) {
  410. if (array_key_exists($property, $this->_belongs_to)) {
  411. $relation = $this->_belongs_to[$property];
  412. $value->dump_model();
  413. $this->{$relation->fk} = $value->{$value->primary_key[0]};
  414. } elseif (array_key_exists($property, $this->_has_one)) {
  415. $relation = $this->_has_one[$property];
  416. $value->{$relation->fk} = $this->{$this->primary_key[0]};
  417. }
  418. } elseif ($property == "source") {
  419. $value = ActiveRecord::sql_item_sanizite($value);
  420. }
  421. }
  422. $this->$property = $value;
  423. }
  424. /**
  425. * Devuelve un valor o un listado dependiendo del tipo de Relaci&oacute;n
  426. *
  427. */
  428. public function __call($method, $args = array())
  429. {
  430. $has_relation = false;
  431. if (substr($method, 0, 8) == "find_by_") {
  432. $field = substr($method, 8);
  433. ActiveRecord::sql_item_sanizite($field);
  434. if (isset($args[0])) {
  435. $arg = array("conditions: $field = {$this->db->add_quotes($args[0]) }");
  436. unset($args[0]);
  437. } else {
  438. $arg = array();
  439. }
  440. return call_user_func_array(array($this, "find_first"), array_merge($arg, $args));
  441. }
  442. if (substr($method, 0, 9) == "count_by_") {
  443. $field = substr($method, 9);
  444. ActiveRecord::sql_item_sanizite($field);
  445. if (isset($args[0])) {
  446. $arg = array("conditions: $field = {$this->db->add_quotes($args[0]) }");
  447. unset($args[0]);
  448. } else {
  449. $arg = array();
  450. }
  451. return call_user_func_array(array($this, "count"), array_merge($arg, $args));
  452. }
  453. if (substr($method, 0, 12) == "find_all_by_") {
  454. $field = substr($method, 12);
  455. ActiveRecord::sql_item_sanizite($field);
  456. if (isset($args[0])) {
  457. $arg = array("conditions: $field = {$this->db->add_quotes($args[0]) }");
  458. unset($args[0]);
  459. } else {
  460. $arg = array();
  461. }
  462. return call_user_func_array(array($this, "find"), array_merge($arg, $args));
  463. }
  464. $model = ereg_replace("^get", "", $method);
  465. $mmodel = Util::uncamelize($model);
  466. if (array_key_exists($mmodel, $this->_belongs_to)) {
  467. $has_relation = true;
  468. $relation = $this->_belongs_to[$mmodel];
  469. return self::get($relation->model)->find_first($this->{$relation->fk});
  470. }
  471. if (array_key_exists($mmodel, $this->_has_many)) {
  472. $has_relation = true;
  473. $relation = $this->_has_many[$mmodel];
  474. if ($this->{$this->primary_key[0]}) {
  475. return self::get($relation->model)->find("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
  476. } else {
  477. return array();
  478. }
  479. }
  480. if (array_key_exists($mmodel, $this->_has_one)) {
  481. $has_relation = true;
  482. $relation = $this->_has_one[$mmodel];
  483. if ($this->{$this->primary_key[0]}) {
  484. return self::get($relation->model)->find_first("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
  485. } else {
  486. return null;
  487. }
  488. }
  489. if (array_key_exists($mmodel, $this->_has_and_belongs_to_many)) {
  490. $has_relation = true;
  491. $relation = $this->_has_and_belongs_to_many[$mmodel];
  492. if ($this->{$this->primary_key[0]}) {
  493. $source = $this->source;
  494. $relation_model = self::get($relation->model);
  495. $relation_model->dump_model();
  496. $relation_source = $relation_model->source;
  497. /**
  498. * Cargo atraves de que tabla se efectuara la relacion
  499. *
  500. */
  501. if (!isset($relation->through)) {
  502. if ($source > $relation_source) {
  503. $relation->through = "{$this->source}_{$relation_source}";
  504. } else {
  505. $relation->through = "{$relation_source}_{$this->source}";
  506. }
  507. }
  508. return self::get($relation->model)->find_all_by_sql("SELECT $relation_source.* FROM $relation_source, {$relation->through}, $source
  509. WHERE {$relation->through}.{$relation->key} = {$this->db->add_quotes($this->{$this->primary_key[0]}) }
  510. AND {$relation->through}.{$relation->fk} = $relation_source.{$relation_model->primary_key[0]}
  511. AND {$relation->through}.{$relation->key} = $source.{$this->primary_key[0]}
  512. ORDER BY $relation_source.{$relation_model->primary_key[0]}");
  513. } else {
  514. return array();
  515. }
  516. }
  517. try {
  518. if (method_exists($this, $method)) {
  519. call_user_func_array(array($this, $method), $args);
  520. } else {
  521. if ($has_relation) {
  522. throw new ActiveRecordException("No existe el modelo '$model' para relacionar con ActiveRecord::{$this->source}");
  523. } else {
  524. throw new ActiveRecordException("No existe el m&eacute;todo '$method' en ActiveRecord::" . get_class($this));
  525. }
  526. }
  527. }
  528. catch(Exception $e) {
  529. $this->exceptions($e);
  530. }
  531. return $this->$method($args);
  532. }
  533. /**
  534. * Se conecta a la base de datos y descarga los meta-datos si es necesario
  535. *
  536. * @param boolean $new_connection
  537. */
  538. protected function _connect($new_connection = false)
  539. {
  540. if (!is_object($this->db) || $new_connection) {
  541. if ($this->database) {
  542. $this->db = DbBase::raw_connect($new_connection, $this->database);
  543. } else {
  544. $this->db = DbBase::raw_connect($new_connection);
  545. }
  546. }
  547. $this->db->debug = $this->debug;
  548. $this->db->logger = $this->logger;
  549. $this->dump();
  550. }
  551. /**
  552. * Cargar los metadatos de la tabla
  553. *
  554. */
  555. public function dump_model()
  556. {
  557. $this->_connect();
  558. }
  559. /**
  560. * Verifica si la tabla definida en $this->source existe
  561. * en la base de datos y la vuelca en dump_info
  562. *
  563. * @return boolean
  564. */
  565. protected function dump()
  566. {
  567. if ($this->_dumped) {
  568. return false;
  569. }
  570. $a = array();
  571. if ($this->source) {
  572. $this->source = str_replace(";", "", strtolower($this->source));
  573. } else {
  574. $this->_model_name();
  575. if (!$this->source) {
  576. return false;
  577. }
  578. }
  579. $table = $this->source;
  580. $schema = $this->schema;
  581. if (!count(self::get_meta_data($this->source))) {
  582. $this->_dumped = true;
  583. $this->_dump_info($table, $schema);
  584. if (!count($this->primary_key)) {
  585. if (!$this->is_view) {
  586. throw new ActiveRecordException("No se ha definido una llave primaria para la tabla '$table' esto imposibilita crear el ActiveRecord para esta entidad");
  587. return false;
  588. }
  589. }
  590. } else {
  591. if (!$this->is_dumped()) {
  592. $this->_dumped = true;
  593. $this->_dump_info($table, $schema);
  594. }
  595. }
  596. return true;
  597. }
  598. /**
  599. * Vuelca la informaci&oacute;n de la tabla $table en la base de datos
  600. * para armar los atributos y meta-data del ActiveRecord
  601. *
  602. * @param string $table
  603. * @return boolean
  604. */
  605. protected function _dump_info($table, $schema = '')
  606. {
  607. $this->_dump_lock = true;
  608. if (!count(self::get_meta_data($table))) {
  609. $meta_data = $this->db->describe_table($table, $schema);
  610. if ($meta_data) {
  611. self::set_meta_data($table, $meta_data);
  612. }
  613. }
  614. foreach(self::get_meta_data($table) as $field) {
  615. $this->fields[] = $field['Field'];
  616. if ($field['Key'] == 'PRI') {
  617. $this->primary_key[] = $field['Field'];
  618. } else $this->non_primary[] = $field['Field'];
  619. /**
  620. * Si se indica que no puede ser nulo, pero se indica un
  621. * valor por defecto, entonces no se incluye en la lista, ya que
  622. * al colocar un valor por defecto, el campo nunca sera nulo
  623. *
  624. */
  625. if ($field['Null'] == 'NO' && !(isset($field['Default']) && $field['Default'])) {
  626. $this->not_null[] = $field['Field'];
  627. }
  628. if (isset($field['Default']) && $field['Default']) {
  629. $this->_with_default[] = $field['Field'];
  630. }
  631. if ($field['Type']) {
  632. $this->_data_type[$field['Field']] = strtolower($field['Type']);
  633. }
  634. if (substr($field['Field'], strlen($field['Field']) - 3, 3) == '_at') {
  635. $this->_at[] = $field['Field'];
  636. }
  637. if (substr($field['Field'], strlen($field['Field']) - 3, 3) == '_in') {
  638. $this->_in[] = $field['Field'];
  639. }
  640. }
  641. $this->attributes_names = $this->fields;
  642. $this->_dump_lock = false;
  643. return true;
  644. }
  645. /**
  646. * Commit a Transaction
  647. *
  648. * @return success
  649. */
  650. public function commit()
  651. {
  652. return $this->db->commit();
  653. }
  654. /**
  655. * Rollback a Transaction
  656. *
  657. * @return success
  658. */
  659. public function rollback()
  660. {
  661. return $this->db->rollback();
  662. }
  663. /**
  664. * Start a transaction in RDBM
  665. *
  666. * @return success
  667. */
  668. public function begin()
  669. {
  670. $this->_connect(true);
  671. return $this->db->begin();
  672. }
  673. /**
  674. * Find all records in this table using a SQL Statement
  675. *
  676. * @param string $sqlQuery
  677. * @return ActiveRecord Cursor
  678. */
  679. public function find_all_by_sql($sqlQuery)
  680. {
  681. $results = array();
  682. foreach($this->db->fetch_all($sqlQuery) as $result) {
  683. $results[] = $this->dump_result($result);
  684. }
  685. return $results;
  686. }
  687. /**
  688. * Find a record in this table using a SQL Statement
  689. *
  690. * @param string $sqlQuery
  691. * @return ActiveRecord Cursor
  692. */
  693. public function find_by_sql($sqlQuery)
  694. {
  695. $row = $this->db->fetch_one($sqlQuery);
  696. if ($row !== false) {
  697. $this->dump_result_self($row);
  698. return $this->dump_result($row);
  699. } else {
  700. return false;
  701. }
  702. }
  703. /**
  704. * Execute a SQL Statement directly
  705. *
  706. * @param string $sqlQuery
  707. * @return int affected
  708. */
  709. public function sql($sqlQuery)
  710. {
  711. return $this->db->query($sqlQuery);
  712. }
  713. /**
  714. * Return Fist Record
  715. *
  716. * @param mixed $what
  717. * @param boolean $debug
  718. *
  719. * Recibe los mismos parametros que find
  720. *
  721. * @return ActiveRecord Cursor
  722. */
  723. public function find_first($what = '')
  724. {
  725. $what = Util::getParams(func_get_args());
  726. $select = "SELECT ";
  727. if (isset($what['columns'])) {
  728. $select.= ActiveRecord::sql_sanizite($what['columns']);
  729. } elseif (isset($what['distinct'])) {
  730. $select.= 'DISTINCT ';
  731. $select.= $what['distinct'] ? ActiveRecord::sql_sanizite($what['distinct']) : join(",", $this->fields);
  732. } else {
  733. $select.= join(",", $this->fields);
  734. }
  735. if ($this->schema) {
  736. $select.= " FROM {$this->schema}.{$this->source}";
  737. } else {
  738. $select.= " FROM {$this->source}";
  739. }
  740. $what['limit'] = 1;
  741. $select.= $this->convert_params_to_sql($what);
  742. $resp = false;
  743. try {
  744. $result = $this->db->fetch_one($select);
  745. if ($result) {
  746. $this->dump_result_self($result);
  747. $resp = $this->dump_result($result);
  748. }
  749. }
  750. catch(Exception $e) {
  751. $this->exceptions($e);
  752. }
  753. return $resp;
  754. }
  755. /**
  756. * Find data on Relational Map table
  757. *
  758. * @param string $what
  759. * @return ActiveRecord Cursor
  760. *
  761. * columns: columnas a utilizar
  762. * conditions : condiciones de busqueda en WHERE
  763. * join: inclusion inner join o outer join
  764. * group : campo para grupo en GROUP BY
  765. * having : condicion para el grupo
  766. * order : campo para criterio de ordenamiento ORDER BY
  767. * distinct: campos para hacer select distinct
  768. */
  769. public function find($what = '')
  770. {
  771. $what = Util::getParams(func_get_args());
  772. $select = "SELECT ";
  773. if (isset($what['columns'])) {
  774. $select.= $what['columns'] ? ActiveRecord::sql_sanizite($what['columns']) : join(",", $this->fields);
  775. } elseif (isset($what['distinct'])) {
  776. $select.= 'DISTINCT ';
  777. $select.= $what['distinct'] ? ActiveRecord::sql_sanizite($what['distinct']) : join(",", $this->fields);
  778. } else {
  779. $select.= join(",", $this->fields);
  780. }
  781. if ($this->schema) {
  782. $select.= " FROM {$this->schema}.{$this->source}";
  783. } else {
  784. $select.= " FROM {$this->source}";
  785. }
  786. $select.= $this->convert_params_to_sql($what);
  787. $results = array();
  788. $all_results = $this->db->in_query($select);
  789. foreach($all_results AS $result) {
  790. $results[] = $this->dump_result($result);
  791. }
  792. $this->count = count($results);
  793. if (isset($what[0]) && is_numeric($what[0])) {
  794. if (!isset($results[0])) {
  795. $this->count = 0;
  796. return false;
  797. } else {
  798. $this->dump_result_self($all_results[0]);
  799. $this->count = 1;
  800. return $results[0];
  801. }
  802. } else {
  803. $this->count = count($results);
  804. return $results;
  805. }
  806. }
  807. /*
  808. * Arma una consulta SQL con el parametro $what, así:
  809. * $what = Util::getParams(func_get_args());
  810. * $select = "SELECT * FROM Clientes";
  811. * $select.= $this->convert_params_to_sql($what);
  812. *
  813. * @param string $what
  814. * @return string
  815. */
  816. public function convert_params_to_sql($what = '')
  817. {
  818. $select = "";
  819. if (is_array($what)) {
  820. if (!isset($what['conditions'])) {
  821. if (!isset($this->primary_key[0]) && (isset($this->id) || $this->is_view)) {
  822. $this->primary_key[0] = "id";
  823. }
  824. ActiveRecord::sql_item_sanizite($this->primary_key[0]);
  825. if (isset($what[0])) {
  826. if (is_numeric($what[0])) {
  827. $what['conditions'] = "{$this->primary_key[0]} = {$this->db->add_quotes($what[0]) }";
  828. } else {
  829. if ($what[0] == '') {
  830. $what['conditions'] = "{$this->primary_key[0]} = ''";
  831. } else {
  832. $what['conditions'] = $what[0];
  833. }
  834. }
  835. }
  836. }
  837. if (isset($what['join']) && $what['join']) {
  838. $select.= " {$what['join']}";
  839. }
  840. if (isset($what['conditions']) && $what['conditions']) {
  841. $select.= " WHERE {$what['conditions']}";
  842. }
  843. if (isset($what['group']) && $what['group']) {
  844. $select.= " GROUP BY {$what['group']}";
  845. }
  846. if (isset($what['having']) && $what['having']) {
  847. $select.= " HAVING {$what['having']}";
  848. }
  849. if (isset($what['order']) && $what['order']) {
  850. ActiveRecord::sql_sanizite($what['order']);
  851. $select.= " ORDER BY {$what['order']}";
  852. }
  853. $limit_args = array($select);
  854. if (isset($what['limit'])) {
  855. array_push($limit_args, "limit: $what[limit]");
  856. }
  857. if (isset($what['offset'])) {
  858. array_push($limit_args, "offset: $what[offset]");
  859. }
  860. if (count($limit_args) > 1) {
  861. $select = call_user_func_array(array($this, 'limit'), $limit_args);
  862. }
  863. } else {
  864. if (strlen($what)) {
  865. if (is_numeric($what)) {
  866. $select.= "WHERE {$this->primary_key[0]} = '$what'";
  867. } else {
  868. $select.= "WHERE $what";
  869. }
  870. }
  871. }
  872. return $select;
  873. }
  874. /*
  875. * Devuelve una clausula LIMIT adecuada al RDBMS empleado
  876. *
  877. * limit: maxima cantidad de elementos a mostrar
  878. * offset: desde que elemento se comienza a mostrar
  879. *
  880. * @param string $sql consulta select
  881. * @return String clausula LIMIT adecuada al RDBMS empleado
  882. */
  883. public function limit($sql)
  884. {
  885. $args = func_get_args();
  886. return call_user_func_array(array($this->db, 'limit'), $args);
  887. }
  888. /**
  889. * Ejecuta un SELECT DISTINCT
  890. * @param string $what
  891. * @return array
  892. *
  893. * Soporta parametros iguales a find
  894. *
  895. */
  896. public function distinct($what = '')
  897. {
  898. $what = Util::getParams(func_get_args());
  899. if ($this->schema) {
  900. $table = $this->schema . "." . $this->source;
  901. } else {
  902. $table = $this->source;
  903. }
  904. if (!isset($what['columns'])) {
  905. $what['columns'] = $what['0'];
  906. } else {
  907. if (!$what['columns']) {
  908. $what['columns'] = $what['0'];
  909. }
  910. }
  911. $what['columns'] = ActiveRecord::sql_sanizite($what['columns']);
  912. $select = "SELECT DISTINCT {$what['columns']} FROM $table ";
  913. /**
  914. * Se elimina el de indice cero ya que por defecto convert_params_to_sql lo considera como una condicion en WHERE
  915. */
  916. unset($what[0]);
  917. $select.= $this->convert_params_to_sql($what);
  918. $results = array();
  919. foreach($this->db->fetch_all($select) as $result) {
  920. $results[] = $result[0];
  921. }
  922. return $results;
  923. }
  924. /**
  925. * Ejecuta una consulta en el RDBM directamente
  926. *
  927. * @param string $sql
  928. * @return resource
  929. */
  930. public function select_one($sql)
  931. {
  932. if (substr(ltrim($sql), 0, 7) != "SELECT") {
  933. $sql = "SELECT " . $sql;
  934. }
  935. $num = $this->db->fetch_one($sql);
  936. return $num[0];
  937. }
  938. static public function static_select_one($sql)
  939. {
  940. $db = db::raw_connect();
  941. if (substr(ltrim($sql), 0, 7) != "SELECT") {
  942. $sql = "SELECT " . $sql;
  943. }
  944. $num = $db->fetch_one($sql);
  945. return $num[0];
  946. }
  947. /**
  948. * Realiza un conteo de filas
  949. *
  950. * @param string $what
  951. * @return integer
  952. */
  953. public function count($what = '')
  954. {
  955. $what = Util::getParams(func_get_args());
  956. if ($this->schema) {
  957. $table = "{$this->schema}.{$this->source}";
  958. } else {
  959. $table = $this->source;
  960. }
  961. if (isset($what['distinct']) && $what['distinct']) {
  962. if (isset($what['group']) || isset($what['order'])) {
  963. $select = "SELECT COUNT(*) FROM (SELECT DISTINCT {$what['distinct']} FROM $table ";
  964. $select.= $this->convert_params_to_sql($what);
  965. $select.= ') AS t ';
  966. } else {
  967. $select = "SELECT COUNT(DISTINCT {$what['distinct']}) FROM $table ";
  968. $select.= $this->convert_params_to_sql($what);
  969. }
  970. } else {
  971. $select = "SELECT COUNT(*) FROM $table ";
  972. $select.= $this->convert_params_to_sql($what);
  973. }
  974. $num = $this->db->fetch_one($select);
  975. return $num[0];
  976. }
  977. /**
  978. * Realiza un promedio sobre el campo $what
  979. *
  980. * @param string $what
  981. * @return array
  982. */
  983. public function average($what = '')
  984. {
  985. $what = Util::getParams(func_get_args());
  986. if (isset($what['column'])) {
  987. if (!$what['column']) {
  988. $what['column'] = $what[0];
  989. }
  990. } else {
  991. $what['column'] = $what[0];
  992. }
  993. unset($what[0]);
  994. ActiveRecord::sql_item_sanizite($what['column']);
  995. if ($this->schema) {
  996. $table = "{$this->schema}.{$this->source}";
  997. } else {
  998. $table = $this->source;
  999. }
  1000. $select = "SELECT AVG({$what['column']}) FROM $table ";
  1001. $select.= $this->convert_params_to_sql($what);
  1002. $num = $this->db->fetch_one($select);
  1003. return $num[0];
  1004. }
  1005. public function sum($what = '')
  1006. {
  1007. $what = Util::getParams(func_get_args());
  1008. if (isset($what['column'])) {
  1009. if (!$what['column']) {
  1010. $what['column'] = $what[0];
  1011. }
  1012. } else {
  1013. $what['column'] = $what[0];
  1014. }
  1015. unset($what[0]);
  1016. ActiveRecord::sql_item_sanizite($what['column']);
  1017. if ($this->schema) {
  1018. $table = "{$this->schema}.{$this->source}";
  1019. } else {
  1020. $table = $this->source;
  1021. }
  1022. $select = "SELECT SUM({$what['column']}) FROM $table ";
  1023. $select.= $this->convert_params_to_sql($what);
  1024. $num = $this->db->fetch_one($select);
  1025. return $num[0];
  1026. }
  1027. /**
  1028. * Busca el valor maximo para el campo $what
  1029. *
  1030. * @param string $what
  1031. * @return mixed
  1032. */
  1033. public function maximum($what = '')
  1034. {
  1035. $what = Util::getParams(func_get_args());
  1036. if (isset($what['column'])) {
  1037. if (!$what['column']) {
  1038. $what['column'] = $what[0];
  1039. }
  1040. } else {
  1041. $what['column'] = $what[0];
  1042. }
  1043. unset($what[0]);
  1044. ActiveRecord::sql_item_sanizite($what['column']);
  1045. if ($this->schema) {
  1046. $table = "{$this->schema}.{$this->source}";
  1047. } else {
  1048. $table = $this->source;
  1049. }
  1050. $select = "SELECT MAX({$what['column']}) FROM $table ";
  1051. $select.= $this->convert_params_to_sql($what);
  1052. $num = $this->db->fetch_one($select);
  1053. return $num[0];
  1054. }
  1055. /**
  1056. * Busca el valor minimo para el campo $what
  1057. *
  1058. * @param string $what
  1059. * @return mixed
  1060. */
  1061. public function minimum($what = '')
  1062. {
  1063. $what = Util::getParams(func_get_args());
  1064. if (isset($what['column'])) {
  1065. if (!$what['column']) {
  1066. $what['column'] = $what[0];
  1067. }
  1068. } else {
  1069. $what['column'] = $what[0];
  1070. }
  1071. unset($what[0]);
  1072. ActiveRecord::sql_item_sanizite($what['column']);
  1073. if ($this->schema) {
  1074. $table = "{$this->schema}.{$this->source}";
  1075. } else {
  1076. $table = $this->source;
  1077. }
  1078. $select = "SELECT MIN({$what['column']}) FROM $table ";
  1079. $select.= $this->convert_params_to_sql($what);
  1080. $num = $this->db->fetch_one($select);
  1081. return $num[0];
  1082. }
  1083. /**
  1084. * Realiza un conteo directo mediante $sql
  1085. *
  1086. * @param string $sqlQuery
  1087. * @return mixed
  1088. */
  1089. public function count_by_sql($sqlQuery)
  1090. {
  1091. $num = $this->db->fetch_one($sqlQuery);
  1092. return $num[0];
  1093. }
  1094. /**
  1095. * Iguala los valores de un resultado de la base de datos
  1096. * en un nuevo objeto con sus correspondientes
  1097. * atributos de la clase
  1098. *
  1099. * @param array $result
  1100. * @return ActiveRecord
  1101. */
  1102. public function dump_result($result){
  1103. $obj = clone $this;
  1104. /**
  1105. * Consulta si la clase es padre de otra y crea el tipo de dato correcto
  1106. */
  1107. if (isset($result['type'])) {
  1108. if (in_array($result['type'], $this->parent_of)) {
  1109. if (class_exists($result['type'])) {
  1110. $obj = new $result['type'];
  1111. unset($result['type']);
  1112. }
  1113. }
  1114. }
  1115. $this->_dump_lock = true;
  1116. if (is_array($result)) {
  1117. foreach($result as $k => $r) {
  1118. if (!is_numeric($k)) {
  1119. $obj->$k = stripslashes($r);
  1120. }
  1121. }
  1122. }
  1123. $this->_dump_lock = false;
  1124. return $obj;
  1125. }
  1126. /**
  1127. * Iguala los valores de un resultado de la base de datos
  1128. * con sus correspondientes atributos de la clase
  1129. *
  1130. * @param array $result
  1131. * @return ActiveRecord
  1132. */
  1133. public function dump_result_self($result)
  1134. {
  1135. $this->_dump_lock = true;
  1136. if (is_array($result)) {
  1137. foreach($result as $k => $r) {
  1138. if (!is_numeric($k)) {
  1139. $this->$k = stripslashes($r);
  1140. }
  1141. }
  1142. }
  1143. $this->_dump_lock = false;
  1144. }
  1145. /**
  1146. * Create a new Row using values from $_REQUEST
  1147. *
  1148. * @param string $form form name for request, equivalent to $_REQUEST[$form]
  1149. * @return boolean success
  1150. */
  1151. public function create_from_request($form = '')
  1152. {
  1153. if ($form) {
  1154. return $this->create($_REQUEST[$form]);
  1155. } else {
  1156. return $this->create($_REQUEST);
  1157. }
  1158. }
  1159. /**
  1160. * Saves a new Row using values from $_REQUEST
  1161. *
  1162. * @param string $form form name for request, equivalent to $_REQUEST[$form]
  1163. * @return boolean success
  1164. */
  1165. public function save_from_request($form = '')
  1166. {
  1167. if ($form) {
  1168. return $this->save($_REQUEST[$form]);
  1169. } else {
  1170. return $this->save($_REQUEST);
  1171. }
  1172. }
  1173. /**
  1174. * Updates a Row using values from $_REQUEST
  1175. *
  1176. * @param string $form form name for request, equivalent to $_REQUEST[$form]
  1177. * @return boolean success
  1178. */
  1179. public function update_from_request($form = '')
  1180. {
  1181. if ($form) {
  1182. return $this->update($_REQUEST[$form]);
  1183. } else {
  1184. return $this->update($_REQUEST);
  1185. }
  1186. }
  1187. /**
  1188. * Creates a new Row in map table
  1189. *
  1190. * @param mixed $values
  1191. * @return success boolean
  1192. */
  1193. public function create()
  1194. {
  1195. if (func_num_args() > 0) {
  1196. $params = Util::getParams(func_get_args());
  1197. $values = (isset($params[0]) && is_array($params[0])) ? $params[0] : $params;
  1198. foreach($this->fields as $field) {
  1199. if (isset($values[$field])) {
  1200. $this->$field = $values[$field];
  1201. }
  1202. }
  1203. }
  1204. if ($this->primary_key[0] == 'id') {
  1205. $this->id = null;
  1206. }
  1207. return $this->save();
  1208. }
  1209. /**
  1210. * Consulta si un determinado registro existe o no
  1211. * en la entidad de la base de datos
  1212. *
  1213. * @return boolean
  1214. */
  1215. function exists($where_pk = '')
  1216. {
  1217. if ($this->schema) {
  1218. $table = "{$this->schema}.{$this->source}";
  1219. } else {
  1220. $table = $this->source;
  1221. }
  1222. if (!$where_pk) {
  1223. $where_pk = array();
  1224. foreach($this->primary_key as $key) {
  1225. if ($this->$key) {
  1226. $where_pk[] = " $key = '{$this->$key}'";
  1227. }
  1228. }
  1229. if (count($where_pk)) {
  1230. $this->_where_pk = join(" AND ", $where_pk);
  1231. } else {
  1232. return 0;
  1233. }
  1234. $query = "SELECT COUNT(*) FROM $table WHERE {$this->_where_pk}";
  1235. } else {
  1236. if (is_numeric($where_pk)) {
  1237. $query = "SELECT(*) FROM $table WHERE id = '$where_pk'";
  1238. } else {
  1239. $query = "SELECT COUNT(*) FROM $table WHERE $where_pk";
  1240. }
  1241. }
  1242. $num = $this->db->fetch_one($query);
  1243. return $num[0];
  1244. }
  1245. /**
  1246. * Saves Information on the ActiveRecord Properties
  1247. * @param array $values array de valores a cargar
  1248. * @return boolean success
  1249. */
  1250. public function save($values=null)
  1251. {
  1252. if ($values) {
  1253. if(!is_array($values))
  1254. $values = Util::getParams(func_get_args());
  1255. foreach($this->fields as $field) {
  1256. if (isset($values[$field])) {
  1257. $this->$field = $values[$field];
  1258. }
  1259. }
  1260. }
  1261. $ex = $this->exists();
  1262. if ($this->schema) {
  1263. $table = $this->schema . "." . $this->source;
  1264. } else {
  1265. $table = $this->source;
  1266. }
  1267. #Run Validation Callbacks Before
  1268. if (method_exists($this, 'before_validation')) {
  1269. if ($this->before_validation() == 'cancel') {
  1270. return false;
  1271. }
  1272. } else {
  1273. if (isset($this->before_validation)) {
  1274. $method = $this->before_validation;
  1275. if ($this->$method() == 'cancel') {
  1276. return false;
  1277. }
  1278. }
  1279. }
  1280. if(!$ex){
  1281. if (method_exists($this, "before_validation_on_create")) {
  1282. if ($this->before_validation_on_create() == 'cancel') {
  1283. return false;
  1284. }
  1285. } else {
  1286. if (isset($this->before_validation_on_create)) {
  1287. $method = $this->before_validation_on_create;
  1288. if ($this->$method() == 'cancel') {
  1289. return false;
  1290. }
  1291. }
  1292. }
  1293. }
  1294. if($ex){
  1295. if (method_exists($this, "before_validation_on_update")) {
  1296. if ($this->before_validation_on_update() == 'cancel') {
  1297. return false;
  1298. }
  1299. } else {
  1300. if (isset($this->before_validation_on_update)) {
  1301. $method = $this->before_validation_on_update;
  1302. if($this->$method() == 'cancel') {
  1303. return false;
  1304. }
  1305. }
  1306. }
  1307. }
  1308. /**
  1309. * Validacion validates_presence
  1310. *
  1311. */
  1312. if(isset($this->_validates['presence_of'])) {
  1313. foreach($this->_validates['presence_of'] as $f => $opt) {
  1314. if (isset($this->$f) && (is_null($this->$f) || $this->$f == '')) {
  1315. if (!$ex && $f == 'id')
  1316. continue;
  1317. if (isset($opt['message'])) {
  1318. Flash::error($opt['message']);
  1319. return false;
  1320. } else {
  1321. $field = isset($opt['field']) ? $opt['field'] : $f;
  1322. Flash::error("Error: El campo $field no puede ser nulo");
  1323. return false;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. /**
  1329. * Recordamos que aqui no aparecen los que tienen valores por defecto,
  1330. * pero sin embargo se debe estar pendiente de validar en las otras verificaciones
  1331. * los campos nulos, ya que en estas si el campo es nulo, realmente se refiere a un campo que
  1332. * debe tomar el valor por defecto
  1333. *
  1334. */
  1335. foreach ($this->not_null as $f) {
  1336. if (!isset($this->$f) || is_null($this->$f) || $this->$f == '') {
  1337. if (!$ex && $f == 'id') {
  1338. continue;
  1339. }
  1340. if (!$ex && in_array($f, $this->_at)) {
  1341. continue;
  1342. }
  1343. if ($ex && in_array($f, $this->_in)) {
  1344. continue;
  1345. }
  1346. Flash::error("Error: El campo $f no puede ser nulo");
  1347. return false;
  1348. }
  1349. }
  1350. /**
  1351. * Validacion validates_length
  1352. *
  1353. */
  1354. if(isset($this->_validates['length_of'])) {
  1355. foreach($this->_validates['length_of'] as $f => $opt) {
  1356. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1357. $field = isset($opt['field']) ? $opt['field'] : $f;
  1358. if (strlen($this->$f) < $opt['min']) {
  1359. if (isset($opt['too_short']))
  1360. Flash::error($opt['too_short']);
  1361. else
  1362. Flash::error("Error: El campo $field debe tener como mínimo $opt[min] caracteres");
  1363. return false;
  1364. }
  1365. if (strlen($this->$f) > $opt['max']) {
  1366. if (isset($opt['too_long']))
  1367. Flash::error($opt['too_long']);
  1368. else
  1369. Flash::error("Error: El campo $field debe tener como máximo $opt[max] caracteres");
  1370. return false;
  1371. }
  1372. }
  1373. }
  1374. }
  1375. /**
  1376. * Validacion validates_inclusion
  1377. *
  1378. */
  1379. foreach($this->_validates['inclusion_in'] as $f => $opt) {
  1380. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1381. if (!in_array($this->$f, $opt['list'])) {
  1382. if (isset($opt['message'])) {
  1383. Flash::error($opt['message']);
  1384. } else {
  1385. $field = isset($opt['field']) ? $opt['field'] : $f;
  1386. Flash::error("$field debe tener un valor entre (" . join(",", $opt['list']) . ")");
  1387. }
  1388. return false;
  1389. }
  1390. }
  1391. }
  1392. /**
  1393. * Validacion validates_exclusion
  1394. *
  1395. */
  1396. foreach($this->_validates['exclusion_of'] as $f => $opt) {
  1397. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1398. if (in_array($this->$f, $opt['list'])) {
  1399. if (isset($opt['message'])) {
  1400. Flash::error($opt['message']);
  1401. } else {
  1402. $field = isset($opt['field']) ? $opt['field'] : $f;
  1403. Flash::error("$field no debe tener un valor entre (" . join(",", $opt['list']) . ")");
  1404. }
  1405. return false;
  1406. }
  1407. }
  1408. }
  1409. /**
  1410. * Validacion validates_numericality
  1411. *
  1412. */
  1413. foreach($this->_validates['numericality_of'] as $f => $opt) {
  1414. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1415. if (!is_numeric($this->$f)) {
  1416. if (isset($opt['message'])) {
  1417. Flash::error($opt['message']);
  1418. } else {
  1419. $field = isset($opt['field']) ? $opt['field'] : $f;
  1420. Flash::error("$field debe tener un valor numérico");
  1421. }
  1422. return false;
  1423. }
  1424. }
  1425. }
  1426. /**
  1427. * Validacion validates_format
  1428. *
  1429. */
  1430. foreach($this->_validates['format_of'] as $f => $opt) {
  1431. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1432. if (!filter_var($this->$f, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>$opt['pattern'])))) {
  1433. if (isset($opt['message'])) {
  1434. Flash::error($opt['message']);
  1435. } else {
  1436. $field = isset($opt['field']) ? $opt['field'] : $f;
  1437. Flash::error("Formato erroneo para $field");
  1438. }
  1439. return false;
  1440. }
  1441. }
  1442. }
  1443. /**
  1444. * Validacion validates_date
  1445. *
  1446. */
  1447. foreach($this->_validates['date_in'] as $f => $opt) {
  1448. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1449. if (!filter_var($this->$f, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>"/^\d{4}[-\/](0[1-9]|1[012])[-\/](0[1-9]|[12][0-9]|3[01])$/")))) {
  1450. if (isset($opt['message'])) {
  1451. Flash::error($opt['message']);
  1452. } else {
  1453. $field = isset($opt['field']) ? $opt['field'] : $f;
  1454. Flash::error("Formato de fecha erroneo para $field");
  1455. }
  1456. return false;
  1457. }
  1458. }
  1459. }
  1460. /**
  1461. * Validacion validates_email
  1462. *
  1463. */
  1464. foreach($this->_validates['email_in'] as $f=>$opt) {
  1465. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1466. if (!filter_var($this->$f, FILTER_VALIDATE_EMAIL)) {
  1467. if (isset($opt['message'])) {
  1468. Flash::error($opt['message']);
  1469. } else {
  1470. $field = isset($opt['field']) ? $opt['field'] : $f;
  1471. Flash::error("Formato de e-mail erroneo en el campo $field");
  1472. }
  1473. return false;
  1474. }
  1475. }
  1476. }
  1477. /**
  1478. * Validacion validates_uniqueness
  1479. *
  1480. */
  1481. foreach($this->_validates['uniqueness_of'] as $f => $opt) {
  1482. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1483. $result = $this->db->fetch_one("SELECT COUNT(*) FROM $table WHERE $f = {$this->db->add_quotes($this->$f)}");
  1484. if ($result[0]) {
  1485. if (isset($opt['message'])) {
  1486. Flash::error($opt['message']);
  1487. } else {
  1488. $field = isset($opt['field']) ? $opt['field'] : $f;
  1489. Flash::error("El valor '{$this->$f}' ya existe para el campo $field");
  1490. }
  1491. return false;
  1492. }
  1493. }
  1494. }
  1495. #Run Validation Callbacks After
  1496. if(!$ex){
  1497. if (method_exists($this, "after_validation_on_create")) {
  1498. if ($this->after_validation_on_create() == 'cancel') {
  1499. return false;
  1500. }
  1501. } else {
  1502. if (isset($this->after_validation_on_create)) {
  1503. $method = $this->after_validation_on_create;
  1504. if ($this->$method() == 'cancel') {
  1505. return false;
  1506. }
  1507. }
  1508. }
  1509. }
  1510. if($ex){
  1511. if (method_exists($this, "after_validation_on_update")) {
  1512. if ($this->after_validation_on_update() == 'cancel') {
  1513. return false;
  1514. }
  1515. } else {
  1516. if (isset($this->after_validation_on_update)) {
  1517. $method = $this->after_validation_on_update;
  1518. if ($this->$method() == 'cancel') return false;
  1519. }
  1520. }
  1521. }
  1522. if (method_exists($this, 'after_validation')) {
  1523. if ($this->after_validation() == 'cancel') {
  1524. return false;
  1525. }
  1526. } else {
  1527. if (isset($this->after_validation)) {
  1528. $method = $this->after_validation;
  1529. if ($this->$method() == 'cancel') {
  1530. return false;
  1531. }
  1532. }
  1533. }
  1534. # Run Before Callbacks
  1535. if (method_exists($this, "before_save")) {
  1536. if ($this->before_save() == 'cancel') {
  1537. return false;
  1538. }
  1539. } else {
  1540. if (isset($this->before_save)) {
  1541. $method = $this->before_save;
  1542. if ($this->$method() == 'cancel') {
  1543. return false;
  1544. }
  1545. }
  1546. }
  1547. if($ex){
  1548. if (method_exists($this, "before_update")) {
  1549. if ($this->before_update() == 'cancel') {
  1550. return false;
  1551. }
  1552. } else {
  1553. if (isset($this->before_update)) {
  1554. $method = $this->before_update;
  1555. if ($this->$method() == 'cancel') {
  1556. return false;
  1557. }
  1558. }
  1559. }
  1560. }
  1561. if(!$ex){
  1562. if (method_exists($this, "before_create")) {
  1563. if ($this->before_create() == 'cancel') {
  1564. return false;
  1565. }
  1566. } else {
  1567. if (isset($this->before_create)) {
  1568. $method = $this->before_create;
  1569. if ($this->$method() == 'cancel') {
  1570. return false;
  1571. }
  1572. }
  1573. }
  1574. }
  1575. $environment = Config::read('databases');
  1576. $config = $environment[$this->get_database()];
  1577. if ($ex) {
  1578. $fields = array();
  1579. $values = array();
  1580. foreach($this->non_primary as $np) {
  1581. $np = ActiveRecord::sql_item_sanizite($np);
  1582. if (in_array($np, $this->_in)) {
  1583. if ($config['type'] == 'oracle') {
  1584. $this->$np = date("Y-m-d");
  1585. } else {
  1586. $this->$np = date("Y-m-d G:i:s");
  1587. }
  1588. }
  1589. if (isset($this->$np)) {
  1590. $fields[] = $np;
  1591. if (is_null($this->$np) || $this->$np == '') {
  1592. $values[] = "NULL";
  1593. } elseif (substr($this->$np, 0, 1) == "%") {
  1594. $values[] = str_replace("%", "", $this->$np);
  1595. } else {
  1596. /**
  1597. * Se debe especificar el formato de fecha en Oracle
  1598. */
  1599. if ($this->_data_type[$np] == 'date' && $config['type'] == 'oracle') {
  1600. $values[] = "TO_DATE(" . $this->db->add_quotes($this->$np) . ", 'YYYY-MM-DD')";
  1601. } else {
  1602. $values[] = $this->db->add_quotes($this->$np);
  1603. }
  1604. }
  1605. }
  1606. }
  1607. $val = $this->db->update($table, $fields, $values, $this->_where_pk);
  1608. } else {
  1609. $fields = array();
  1610. $values = array();
  1611. foreach($this->fields as $field) {
  1612. if ($field != 'id' && !$this->id) {
  1613. if (in_array($field, $this->_at)) {
  1614. if ($config['type'] == 'oracle') {
  1615. $this->$field = date("Y-m-d");
  1616. } else {
  1617. $this->$field = date("Y-m-d G:i:s");
  1618. }
  1619. }
  1620. if (in_array($field, $this->_in)) {
  1621. unset($this->$field);
  1622. }
  1623. $use_default = in_array($field, $this->_with_default) && isset($this->$field) && (is_null($this->$field) || $this->$field == '');
  1624. if($this->_data_type[$field] == 'datetime' && $config['type'] == 'mysql'){
  1625. $this->$field = date("Y-m-d G:i:s",strtotime($this->$field));
  1626. }
  1627. if (isset($this->$field) && !$use_default) {
  1628. $fields[] = ActiveRecord::sql_sanizite($field);
  1629. if (substr($this->$field, 0, 1) == "%") {
  1630. $values[] = str_replace("%", "", $this->$field);
  1631. } else {
  1632. if ($this->is_a_numeric_type($field) || $this->$field == null) {
  1633. $values[] = addslashes($this->$field !== '' && $this->$field !== null ? $this->$field : "NULL");
  1634. } else {
  1635. if ($this->_data_type[$field] == 'date' && $config['type'] == 'oracle') {
  1636. /**
  1637. * Se debe especificar el formato de fecha en Oracle
  1638. */
  1639. $values[] = "TO_DATE(" . $this->db->add_quotes($this->$field) . ", 'YYYY-MM-DD')";
  1640. } else {
  1641. if (!is_null($this->$field) && $this->$field != '') {
  1642. $values[] = $this->db->add_quotes($this->$field);
  1643. } else {
  1644. $values[] = "NULL";
  1645. }
  1646. }
  1647. }
  1648. }
  1649. }
  1650. } else {
  1651. /**
  1652. * Campos autonumericos en Oracle deben utilizar una sequencia auxiliar
  1653. */
  1654. if ($config['type'] == 'oracle') {
  1655. if (!$this->id) {
  1656. $fields[] = "id";
  1657. $values[] = $this->source . "_id_seq.NEXTVAL";
  1658. }
  1659. }
  1660. if ($config['type'] == 'informix') {
  1661. if (!$this->id) {
  1662. $fields[] = "id";
  1663. $values[] = 0;
  1664. }
  1665. }
  1666. }
  1667. }
  1668. $val = $this->db->insert($table, $values, $fields);
  1669. }
  1670. if (!isset($config['pdo']) && $config['type'] == 'oracle') {
  1671. $this->commit();
  1672. }
  1673. if (!$ex) {
  1674. //$this->db->logger = true;
  1675. $m = $this->db->last_insert_id($table, $this->primary_key[0]);
  1676. $this->find_first($m);
  1677. }
  1678. if ($val) {
  1679. if($ex){
  1680. if (method_exists($this, "after_update")) {
  1681. if ($this->after_update() == 'cancel') {
  1682. return false;
  1683. }
  1684. } else {
  1685. if (isset($this->after_update)) {
  1686. $method = $this->after_update;
  1687. if ($this->$method() == 'cancel') {
  1688. return false;
  1689. }
  1690. }
  1691. }
  1692. }
  1693. if(!$ex){
  1694. if (method_exists($this, "after_create")) {
  1695. if ($this->after_create() == 'cancel') {
  1696. return false;
  1697. }
  1698. } else {
  1699. if (isset($this->after_create)) {
  1700. $method = $this->after_create;
  1701. if ($this->$method() == 'cancel') {
  1702. return false;
  1703. }
  1704. }
  1705. }
  1706. }
  1707. if (method_exists($this, "after_save")) {
  1708. if ($this->after_save() == 'cancel') {
  1709. return false;
  1710. }
  1711. } else {
  1712. if (isset($this->after_save)) {
  1713. $method = $this->after_save;
  1714. if ($this->$method() == 'cancel') {
  1715. return false;
  1716. }
  1717. }
  1718. }
  1719. return $val;
  1720. } else {
  1721. return false;
  1722. }
  1723. }
  1724. /**
  1725. * Find All data in the Relational Table
  1726. *
  1727. * @param string $field
  1728. * @param string $value
  1729. * @return ActiveRecod Cursor
  1730. */
  1731. function find_all_by($field, $value)
  1732. {
  1733. ActiveRecord::sql_item_sanizite($field);
  1734. return $this->find("conditions: $field = {$this->db->add_quotes($value) }");
  1735. }
  1736. /**
  1737. * Updates Data in the Relational Table
  1738. *
  1739. * @param mixed $values
  1740. * @return boolean sucess
  1741. */
  1742. function update()
  1743. {
  1744. if (func_num_args() > 0) {
  1745. $params = Util::getParams(func_get_args());
  1746. $values = (isset($params[0]) && is_array($params[0])) ? $params[0] : $params;
  1747. foreach($this->fields as $field) {
  1748. if (isset($values[$field])) {
  1749. $this->$field = $values[$field];
  1750. }
  1751. }
  1752. }
  1753. if ($this->exists()) {
  1754. if (method_exists($this, 'before_change')) {
  1755. $obj = clone $this;
  1756. if($this->before_change($obj->find($this->id)) == 'cancel'){
  1757. return false;
  1758. }
  1759. unset($obj);
  1760. }
  1761. if($this->save()){
  1762. if (method_exists($this, 'after_change')) {
  1763. if ($this->after_change($this) == 'cancel') {
  1764. return false;
  1765. }
  1766. }
  1767. return true;
  1768. }
  1769. } else {
  1770. Flash::error('No se puede actualizar porque el registro no existe');
  1771. return false;
  1772. }
  1773. }
  1774. /**
  1775. * Deletes data from Relational Map Table
  1776. *
  1777. * @param mixed $what
  1778. */
  1779. public function delete($what = '')
  1780. {
  1781. if (func_num_args() > 1) {
  1782. $what = Util::getParams(func_get_args());
  1783. }
  1784. if ($this->schema) {
  1785. $table = $this->schema . "." . $this->source;
  1786. } else {
  1787. $table = $this->source;
  1788. }
  1789. $conditions = "";
  1790. if (is_array($what)) {
  1791. if ($what["conditions"]) {
  1792. $conditions = $what["conditions"];
  1793. }
  1794. } else {
  1795. if (is_numeric($what)) {
  1796. ActiveRecord::sql_sanizite($this->primary_key[0]);
  1797. $conditions = "{$this->primary_key[0]} = '$what'";
  1798. } else {
  1799. if ($what) {
  1800. $conditions = $what;
  1801. } else {
  1802. ActiveRecord::sql_sanizite($this->primary_key[0]);
  1803. $conditions = "{$this->primary_key[0]} = '{$this->{$this->primary_key[0]}}'";
  1804. }
  1805. }
  1806. }
  1807. if (method_exists($this, "before_delete")) {
  1808. if ($this->id) {
  1809. $this->find($this->id);
  1810. }
  1811. if ($this->before_delete() == 'cancel') {
  1812. return false;
  1813. }
  1814. } else {
  1815. if (isset($this->before_delete)) {
  1816. if ($this->id) {
  1817. $this->find($this->id);
  1818. }
  1819. $method = $this->before_delete;
  1820. if ($this->$method() == 'cancel') {
  1821. return false;
  1822. }
  1823. }
  1824. }
  1825. $val = $this->db->delete($table, $conditions);
  1826. if ($val) {
  1827. if (method_exists($this, "after_delete")) {
  1828. if ($this->after_delete() == 'cancel') {
  1829. return false;
  1830. }
  1831. } else {
  1832. if (isset($this->after_delete)) {
  1833. $method = $this->after_delete;
  1834. if ($this->$method() == 'cancel') {
  1835. return false;
  1836. }
  1837. }
  1838. }
  1839. }
  1840. return $val;
  1841. }
  1842. /**
  1843. * Actualiza todos los atributos de la entidad
  1844. * $Clientes->update_all("estado='A', fecha='2005-02-02'", "id>100");
  1845. * $Clientes->update_all("estado='A', fecha='2005-02-02'", "id>100", "limit: 10");
  1846. *
  1847. * @param string $values
  1848. */
  1849. public function update_all($values) {
  1850. $params = array();
  1851. if ($this->schema) {
  1852. $table = $this->schema . "." . $this->source;
  1853. } else {
  1854. $table = $this->source;
  1855. }
  1856. if (func_num_args() > 1) {
  1857. $params = Util::getParams(func_get_args());
  1858. }
  1859. if (!isset($params['conditions']) || !$params['conditions']) {
  1860. if (isset($params[1])) {
  1861. $params['conditions'] = $params[1];
  1862. } else {
  1863. $params['conditions'] = "";
  1864. }
  1865. }
  1866. if ($params['conditions']) {
  1867. $params['conditions'] = " WHERE " . $params['conditions'];
  1868. }
  1869. $sql = "UPDATE $table SET $values {$params['conditions']}";
  1870. $limit_args = array($sql);
  1871. if (isset($params['limit'])) {
  1872. array_push($limit_args, "limit: $params[limit]");
  1873. }
  1874. if (isset($params['offset'])) {
  1875. array_push($limit_args, "offset: $params[offset]");
  1876. }
  1877. if (count($limit_args) > 1) {
  1878. $sql = call_user_func_array(array($this, 'limit'), $limit_args);
  1879. }
  1880. $environment = Config::read('databases');
  1881. $config = $environment[$this->get_database()];
  1882. if (!isset($config->pdo) || !$config->pdo) {
  1883. if ($config['type'] == "informix") {
  1884. $this->db->set_return_rows(false);
  1885. }
  1886. }
  1887. return $this->db->query($sql);
  1888. }
  1889. /**
  1890. * Delete All data from Relational Map Table
  1891. *
  1892. * @param string $conditions
  1893. * @return boolean
  1894. */
  1895. public function delete_all($conditions = '') {
  1896. $limit = "";
  1897. if ($this->schema) {
  1898. $table = $this->schema . "." . $this->source;
  1899. } else {
  1900. $table = $this->source;
  1901. }
  1902. if (func_num_args() > 1) {
  1903. $params = Util::getParams(func_get_args());
  1904. $limit_args = array($select);
  1905. if (isset($params['limit'])) {
  1906. array_push($limit_args, "limit: $params[limit]");
  1907. }
  1908. if (isset($params['offset'])) {
  1909. array_push($limit_args, "offset: $params[offset]");
  1910. }
  1911. if (count($limit_args) > 1) {
  1912. $select = call_user_func_array(array($this, 'limit'), $limit_args);
  1913. }
  1914. }
  1915. return $this->db->delete($table, $conditions);
  1916. }
  1917. /**
  1918. * *********************************************************************************
  1919. * Metodos de Debug
  1920. * *********************************************************************************
  1921. */
  1922. /**
  1923. * Imprime una version humana de los valores de los campos
  1924. * del modelo en una sola linea
  1925. *
  1926. */
  1927. public function inspect() {
  1928. $inspect = array();
  1929. foreach($this->fields as $field) {
  1930. if (!is_array($field)) {
  1931. $inspect[] = "$field: {$this->$field}";
  1932. }
  1933. }
  1934. return join(", ", $inspect