PageRenderTime 36ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/core/libs/kumbia_active_record/kumbia_active_record.php

https://github.com/argordmel/Daily-Content-Manager
PHP | 2489 lines | 1608 code | 37 blank | 844 comment | 532 complexity | 9113c424374c2e16c5f50cf3d6c10bf3 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-3.0, LGPL-2.1
  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. * @see Db
  25. */
  26. require CORE_PATH . 'libs/db/db.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 KumbiaActiveRecord
  68. {
  69. //Soportados
  70. /**
  71. * Resource de conexion a la base de datos
  72. *
  73. * @var DbBase
  74. */
  75. protected $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. protected $count;
  100. /**
  101. * Nombres de los atributos de la entidad
  102. *
  103. * @var array
  104. */
  105. protected $fields = array();
  106. /**
  107. * LLaves primarias de la entidad
  108. *
  109. * @var array
  110. */
  111. protected $primary_key = array();
  112. /**
  113. * Campos que no son llave primaria
  114. *
  115. * @var array
  116. */
  117. protected $non_primary = array();
  118. /**
  119. * Campos que no permiten nulos
  120. *
  121. * @var array
  122. */
  123. protected $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. protected $alias = 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. protected $is_view = false;
  143. /**
  144. * Indica si el modelo esta en modo debug
  145. *
  146. * @var boolean
  147. */
  148. protected $debug = false;
  149. /**
  150. * Indica si se logearan los mensajes generados por la clase
  151. *
  152. * @var mixed
  153. */
  154. protected $logger = false;
  155. /**
  156. * Indica si los datos del modelo deben ser persistidos
  157. *
  158. * @var boolean
  159. */
  160. protected $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. protected $parent_of = array();
  244. /**
  245. * Persistance Models Meta-data
  246. */
  247. protected static $_models = array();
  248. /**
  249. * Persistance Models Meta-data
  250. */
  251. protected 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 = preg_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 KumbiaException("No existe el modelo '$model' para relacionar con ActiveRecord::{$this->source}");
  523. } else {
  524. throw new KumbiaException("No existe el mé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. $this->db = Db::factory($this->database, $new_connection);
  542. }
  543. $this->db->debug = $this->debug;
  544. $this->db->logger = $this->logger;
  545. $this->dump();
  546. }
  547. /**
  548. * Cargar los metadatos de la tabla
  549. *
  550. */
  551. public function dump_model()
  552. {
  553. $this->_connect();
  554. }
  555. /**
  556. * Verifica si la tabla definida en $this->source existe
  557. * en la base de datos y la vuelca en dump_info
  558. *
  559. * @return boolean
  560. */
  561. protected function dump()
  562. {
  563. if ($this->_dumped) {
  564. return false;
  565. }
  566. $a = array();
  567. if ($this->source) {
  568. $this->source = str_replace(";", '', strtolower($this->source));
  569. } else {
  570. $this->_model_name();
  571. if (!$this->source) {
  572. return false;
  573. }
  574. }
  575. $table = $this->source;
  576. $schema = $this->schema;
  577. if (!count(self::get_meta_data($this->source))) {
  578. $this->_dumped = true;
  579. $this->_dump_info($table, $schema);
  580. if (!count($this->primary_key)) {
  581. if (!$this->is_view) {
  582. throw new KumbiaException("No se ha definido una llave primaria para la tabla '$table' esto imposibilita crear el ActiveRecord para esta entidad");
  583. return false;
  584. }
  585. }
  586. } else {
  587. if (!$this->is_dumped()) {
  588. $this->_dumped = true;
  589. $this->_dump_info($table, $schema);
  590. }
  591. }
  592. return true;
  593. }
  594. /**
  595. * Vuelca la informaci&oacute;n de la tabla $table en la base de datos
  596. * para armar los atributos y meta-data del ActiveRecord
  597. *
  598. * @param string $table
  599. * @return boolean
  600. */
  601. protected function _dump_info($table, $schema = '')
  602. {
  603. $this->_dump_lock = true;
  604. if (!count(self::get_meta_data($table))) {
  605. $meta_data = $this->db->describe_table($table, $schema);
  606. if ($meta_data) {
  607. self::set_meta_data($table, $meta_data);
  608. }
  609. }
  610. foreach(self::get_meta_data($table) as $field) {
  611. $this->fields[] = $field['Field'];
  612. $aliasAux = $field['Field'];
  613. if ($field['Key'] == 'PRI') {
  614. $this->primary_key[] = $field['Field'];
  615. $this->alias[$field['Field']] = 'Código';
  616. } else $this->non_primary[] = $field['Field'];
  617. /**
  618. * Si se indica que no puede ser nulo, pero se indica un
  619. * valor por defecto, entonces no se incluye en la lista, ya que
  620. * al colocar un valor por defecto, el campo nunca sera nulo
  621. *
  622. */
  623. if ($field['Null'] == 'NO' && !(isset($field['Default']) && $field['Default'])) {
  624. $this->not_null[] = $field['Field'];
  625. }
  626. if (isset($field['Default']) && $field['Default']) {
  627. $this->_with_default[] = $field['Field'];
  628. }
  629. if ($field['Type']) {
  630. $this->_data_type[$field['Field']] = strtolower($field['Type']);
  631. }
  632. if (substr($field['Field'], strlen($field['Field']) - 3, 3) == '_at') {
  633. $this->_at[] = $field['Field'];
  634. $aliasAux = substr($field['Field'], 0, -3);
  635. }
  636. if (substr($field['Field'], strlen($field['Field']) - 3, 3) == '_in') {
  637. $this->_in[] = $field['Field'];
  638. $aliasAux = substr($field['Field'], 0, -3);
  639. }
  640. if (substr($field['Field'], strlen($field['Field']) - 3, 3) == '_id') {
  641. $aliasAux = substr($field['Field'], 0, -3);
  642. }
  643. //humanizando el alias
  644. $this->alias[$field['Field']] = ucwords(strtr($aliasAux,'_-',' '));
  645. }
  646. $this->_dump_lock = false;
  647. return true;
  648. }
  649. /**
  650. * Retorna un array de los campos (fields) de una tabla Humanizados
  651. *
  652. * @param $key
  653. * @return array
  654. */
  655. public function get_alias($key=null)
  656. {
  657. if($key && array_key_exists($key, $this->alias)){
  658. return $this->alias[$key];
  659. } else {
  660. throw new KumbiaException("No se pudo obtener el Alias, porque el key: \"$key\" no existe.");
  661. }
  662. return $this->alias;
  663. }
  664. /**
  665. * Asigna un nuevo valor al alias dado un key
  666. *
  667. * @param string $key
  668. * @param string $value
  669. */
  670. public function set_alias($key=null, $value=null)
  671. {
  672. if($key && array_key_exists($key, $this->alias)){
  673. $this->alias[$key] = $value;
  674. } else {
  675. throw new KumbiaException("No se pudo asignar el nuevo valor al Alias, porque el key: \"$key\" no existe.");
  676. }
  677. }
  678. /**
  679. * Commit a Transaction
  680. *
  681. * @return success
  682. */
  683. public function commit()
  684. {
  685. return $this->db->commit();
  686. }
  687. /**
  688. * Rollback a Transaction
  689. *
  690. * @return success
  691. */
  692. public function rollback()
  693. {
  694. return $this->db->rollback();
  695. }
  696. /**
  697. * Start a transaction in RDBM
  698. *
  699. * @return success
  700. */
  701. public function begin()
  702. {
  703. $this->_connect(true);
  704. return $this->db->begin();
  705. }
  706. /**
  707. * Find all records in this table using a SQL Statement
  708. *
  709. * @param string $sqlQuery
  710. * @return ActiveRecord Cursor
  711. */
  712. public function find_all_by_sql($sqlQuery)
  713. {
  714. $results = array();
  715. foreach($this->db->fetch_all($sqlQuery) as $result) {
  716. $results[] = $this->dump_result($result);
  717. }
  718. return $results;
  719. }
  720. /**
  721. * Find a record in this table using a SQL Statement
  722. *
  723. * @param string $sqlQuery
  724. * @return ActiveRecord Cursor
  725. */
  726. public function find_by_sql($sqlQuery)
  727. {
  728. $row = $this->db->fetch_one($sqlQuery);
  729. if ($row !== false) {
  730. $this->dump_result_self($row);
  731. return $this->dump_result($row);
  732. } else {
  733. return false;
  734. }
  735. }
  736. /**
  737. * Execute a SQL Statement directly
  738. *
  739. * @param string $sqlQuery
  740. * @return int affected
  741. */
  742. public function sql($sqlQuery)
  743. {
  744. return $this->db->query($sqlQuery);
  745. }
  746. /**
  747. * Return Fist Record
  748. *
  749. * @param mixed $what
  750. * @param boolean $debug
  751. *
  752. * Recibe los mismos parametros que find
  753. *
  754. * @return ActiveRecord Cursor
  755. */
  756. public function find_first($what = '')
  757. {
  758. $what = Util::getParams(func_get_args());
  759. $select = "SELECT ";
  760. if (isset($what['columns'])) {
  761. $select.= ActiveRecord::sql_sanizite($what['columns']);
  762. } elseif (isset($what['distinct'])) {
  763. $select.= 'DISTINCT ';
  764. $select.= $what['distinct'] ? ActiveRecord::sql_sanizite($what['distinct']) : join(",", $this->fields);
  765. } else {
  766. $select.= join(",", $this->fields);
  767. }
  768. if ($this->schema) {
  769. $select.= " FROM {$this->schema}.{$this->source}";
  770. } else {
  771. $select.= " FROM {$this->source}";
  772. }
  773. $what['limit'] = 1;
  774. $select.= $this->convert_params_to_sql($what);
  775. $resp = false;
  776. try {
  777. $result = $this->db->fetch_one($select);
  778. if ($result) {
  779. $this->dump_result_self($result);
  780. $resp = $this->dump_result($result);
  781. }
  782. }
  783. catch(Exception $e) {
  784. $this->exceptions($e);
  785. }
  786. return $resp;
  787. }
  788. /**
  789. * Find data on Relational Map table
  790. *
  791. * @param string $what
  792. * @return ActiveRecord Cursor
  793. *
  794. * columns: columnas a utilizar
  795. * conditions : condiciones de busqueda en WHERE
  796. * join: inclusion inner join o outer join
  797. * group : campo para grupo en GROUP BY
  798. * having : condicion para el grupo
  799. * order : campo para criterio de ordenamiento ORDER BY
  800. * distinct: campos para hacer select distinct
  801. */
  802. public function find($what = '')
  803. {
  804. $what = Util::getParams(func_get_args());
  805. $select = "SELECT ";
  806. if (isset($what['columns'])) {
  807. $select.= $what['columns'] ? ActiveRecord::sql_sanizite($what['columns']) : join(",", $this->fields);
  808. } elseif (isset($what['distinct'])) {
  809. $select.= 'DISTINCT ';
  810. $select.= $what['distinct'] ? ActiveRecord::sql_sanizite($what['distinct']) : join(",", $this->fields);
  811. } else {
  812. $select.= join(",", $this->fields);
  813. }
  814. if ($this->schema) {
  815. $select.= " FROM {$this->schema}.{$this->source}";
  816. } else {
  817. $select.= " FROM {$this->source}";
  818. }
  819. $select.= $this->convert_params_to_sql($what);
  820. $results = array();
  821. $all_results = $this->db->in_query($select);
  822. foreach($all_results AS $result) {
  823. $results[] = $this->dump_result($result);
  824. }
  825. $this->count = count($results, COUNT_NORMAL);
  826. if (isset($what[0]) && is_numeric($what[0])) {
  827. if (!isset($results[0])) {
  828. $this->count = 0;
  829. return false;
  830. } else {
  831. $this->dump_result_self($all_results[0]);
  832. $this->count = 1;
  833. return $results[0];
  834. }
  835. } else {
  836. $this->count = count($results, COUNT_NORMAL);
  837. return $results;
  838. }
  839. }
  840. /*
  841. * Arma una consulta SQL con el parametro $what, así:
  842. * $what = Util::getParams(func_get_args());
  843. * $select = "SELECT * FROM Clientes";
  844. * $select.= $this->convert_params_to_sql($what);
  845. *
  846. * @param string $what
  847. * @return string
  848. */
  849. public function convert_params_to_sql($what = '')
  850. {
  851. $select = '';
  852. if (is_array($what)) {
  853. if (!isset($what['conditions'])) {
  854. if (!isset($this->primary_key[0]) && (isset($this->id) || $this->is_view)) {
  855. $this->primary_key[0] = "id";
  856. }
  857. ActiveRecord::sql_item_sanizite($this->primary_key[0]);
  858. if (isset($what[0])) {
  859. if (is_numeric($what[0])) {
  860. $what['conditions'] = "{$this->primary_key[0]} = {$this->db->add_quotes($what[0]) }";
  861. } else {
  862. if ($what[0] == '') {
  863. $what['conditions'] = "{$this->primary_key[0]} = ''";
  864. } else {
  865. $what['conditions'] = $what[0];
  866. }
  867. }
  868. }
  869. }
  870. if (isset($what['join'])) {
  871. $select.= " {$what['join']}";
  872. }
  873. if (isset($what['conditions'])) {
  874. $select.= " WHERE {$what['conditions']}";
  875. }
  876. if (isset($what['group'])) {
  877. $select.= " GROUP BY {$what['group']}";
  878. }
  879. if (isset($what['having'])) {
  880. $select.= " HAVING {$what['having']}";
  881. }
  882. if (isset($what['order'])) {
  883. ActiveRecord::sql_sanizite($what['order']);
  884. $select.= " ORDER BY {$what['order']}";
  885. }
  886. $limit_args = array($select);
  887. if (isset($what['limit'])) {
  888. array_push($limit_args, "limit: $what[limit]");
  889. }
  890. if (isset($what['offset'])) {
  891. array_push($limit_args, "offset: $what[offset]");
  892. }
  893. if (count($limit_args) > 1) {
  894. $select = call_user_func_array(array($this, 'limit'), $limit_args);
  895. }
  896. } else {
  897. if (strlen($what)) {
  898. if (is_numeric($what)) {
  899. $select.= "WHERE {$this->primary_key[0]} = '$what'";
  900. } else {
  901. $select.= "WHERE $what";
  902. }
  903. }
  904. }
  905. return $select;
  906. }
  907. /*
  908. * Devuelve una clausula LIMIT adecuada al RDBMS empleado
  909. *
  910. * limit: maxima cantidad de elementos a mostrar
  911. * offset: desde que elemento se comienza a mostrar
  912. *
  913. * @param string $sql consulta select
  914. * @return String clausula LIMIT adecuada al RDBMS empleado
  915. */
  916. public function limit($sql)
  917. {
  918. $args = func_get_args();
  919. return call_user_func_array(array($this->db, 'limit'), $args);
  920. }
  921. /**
  922. * Ejecuta un SELECT DISTINCT
  923. * @param string $what
  924. * @return array
  925. *
  926. * Soporta parametros iguales a find
  927. *
  928. */
  929. public function distinct($what = '')
  930. {
  931. $what = Util::getParams(func_get_args());
  932. if ($this->schema) {
  933. $table = $this->schema . "." . $this->source;
  934. } else {
  935. $table = $this->source;
  936. }
  937. if (!isset($what['columns'])) {
  938. $what['columns'] = $what['0'];
  939. } else {
  940. if (!$what['columns']) {
  941. $what['columns'] = $what['0'];
  942. }
  943. }
  944. $what['columns'] = ActiveRecord::sql_sanizite($what['columns']);
  945. $select = "SELECT DISTINCT {$what['columns']} FROM $table ";
  946. /**
  947. * Se elimina el de indice cero ya que por defecto convert_params_to_sql lo considera como una condicion en WHERE
  948. */
  949. unset($what[0]);
  950. $select.= $this->convert_params_to_sql($what);
  951. $results = array();
  952. foreach($this->db->fetch_all($select) as $result) {
  953. $results[] = $result[0];
  954. }
  955. return $results;
  956. }
  957. /**
  958. * Ejecuta una consulta en el RDBM directamente
  959. *
  960. * @param string $sql
  961. * @return resource
  962. */
  963. static public function static_select_one($sql)
  964. {
  965. $db = Db::factory();
  966. if (substr(ltrim($sql), 0, 7) != "SELECT") {
  967. $sql = "SELECT " . $sql;
  968. }
  969. $num = $db->fetch_one($sql);
  970. return $num[0];
  971. }
  972. /**
  973. * Realiza un conteo de filas
  974. *
  975. * @param string $what
  976. * @return integer
  977. */
  978. public function count($what = '')
  979. {
  980. $what = Util::getParams(func_get_args());
  981. if ($this->schema) {
  982. $table = "{$this->schema}.{$this->source}";
  983. } else {
  984. $table = $this->source;
  985. }
  986. if (isset($what['distinct']) && $what['distinct']) {
  987. if (isset($what['group']) || isset($what['order'])) {
  988. $select = "SELECT COUNT(*) FROM (SELECT DISTINCT {$what['distinct']} FROM $table ";
  989. $select.= $this->convert_params_to_sql($what);
  990. $select.= ') AS t ';
  991. } else {
  992. $select = "SELECT COUNT(DISTINCT {$what['distinct']}) FROM $table ";
  993. $select.= $this->convert_params_to_sql($what);
  994. }
  995. } else {
  996. $select = "SELECT COUNT(*) FROM $table ";
  997. $select.= $this->convert_params_to_sql($what);
  998. }
  999. $num = $this->db->fetch_one($select);
  1000. return $num[0];
  1001. }
  1002. /**
  1003. * Realiza un promedio sobre el campo $what
  1004. *
  1005. * @param string $what
  1006. * @return array
  1007. */
  1008. public function average($what = '')
  1009. {
  1010. $what = Util::getParams(func_get_args());
  1011. if (isset($what['column'])) {
  1012. if (!$what['column']) {
  1013. $what['column'] = $what[0];
  1014. }
  1015. } else {
  1016. $what['column'] = $what[0];
  1017. }
  1018. unset($what[0]);
  1019. ActiveRecord::sql_item_sanizite($what['column']);
  1020. if ($this->schema) {
  1021. $table = "{$this->schema}.{$this->source}";
  1022. } else {
  1023. $table = $this->source;
  1024. }
  1025. $select = "SELECT AVG({$what['column']}) FROM $table ";
  1026. $select.= $this->convert_params_to_sql($what);
  1027. $num = $this->db->fetch_one($select);
  1028. return $num[0];
  1029. }
  1030. public function sum($what = '')
  1031. {
  1032. $what = Util::getParams(func_get_args());
  1033. if (isset($what['column'])) {
  1034. if (!$what['column']) {
  1035. $what['column'] = $what[0];
  1036. }
  1037. } else {
  1038. $what['column'] = $what[0];
  1039. }
  1040. unset($what[0]);
  1041. ActiveRecord::sql_item_sanizite($what['column']);
  1042. if ($this->schema) {
  1043. $table = "{$this->schema}.{$this->source}";
  1044. } else {
  1045. $table = $this->source;
  1046. }
  1047. $select = "SELECT SUM({$what['column']}) FROM $table ";
  1048. $select.= $this->convert_params_to_sql($what);
  1049. $num = $this->db->fetch_one($select);
  1050. return $num[0];
  1051. }
  1052. /**
  1053. * Busca el valor maximo para el campo $what
  1054. *
  1055. * @param string $what
  1056. * @return mixed
  1057. */
  1058. public function maximum($what = '')
  1059. {
  1060. $what = Util::getParams(func_get_args());
  1061. if (isset($what['column'])) {
  1062. if (!$what['column']) {
  1063. $what['column'] = $what[0];
  1064. }
  1065. } else {
  1066. $what['column'] = $what[0];
  1067. }
  1068. unset($what[0]);
  1069. ActiveRecord::sql_item_sanizite($what['column']);
  1070. if ($this->schema) {
  1071. $table = "{$this->schema}.{$this->source}";
  1072. } else {
  1073. $table = $this->source;
  1074. }
  1075. $select = "SELECT MAX({$what['column']}) FROM $table ";
  1076. $select.= $this->convert_params_to_sql($what);
  1077. $num = $this->db->fetch_one($select);
  1078. return $num[0];
  1079. }
  1080. /**
  1081. * Busca el valor minimo para el campo $what
  1082. *
  1083. * @param string $what
  1084. * @return mixed
  1085. */
  1086. public function minimum($what = '')
  1087. {
  1088. $what = Util::getParams(func_get_args());
  1089. if (isset($what['column'])) {
  1090. if (!$what['column']) {
  1091. $what['column'] = $what[0];
  1092. }
  1093. } else {
  1094. $what['column'] = $what[0];
  1095. }
  1096. unset($what[0]);
  1097. ActiveRecord::sql_item_sanizite($what['column']);
  1098. if ($this->schema) {
  1099. $table = "{$this->schema}.{$this->source}";
  1100. } else {
  1101. $table = $this->source;
  1102. }
  1103. $select = "SELECT MIN({$what['column']}) FROM $table ";
  1104. $select.= $this->convert_params_to_sql($what);
  1105. $num = $this->db->fetch_one($select);
  1106. return $num[0];
  1107. }
  1108. /**
  1109. * Realiza un conteo directo mediante $sql
  1110. *
  1111. * @param string $sqlQuery
  1112. * @return mixed
  1113. */
  1114. public function count_by_sql($sqlQuery)
  1115. {
  1116. $num = $this->db->fetch_one($sqlQuery);
  1117. return $num[0];
  1118. }
  1119. /**
  1120. * Iguala los valores de un resultado de la base de datos
  1121. * en un nuevo objeto con sus correspondientes
  1122. * atributos de la clase
  1123. *
  1124. * @param array $result
  1125. * @return ActiveRecord
  1126. */
  1127. public function dump_result($result){
  1128. $obj = clone $this;
  1129. /**
  1130. * Consulta si la clase es padre de otra y crea el tipo de dato correcto
  1131. */
  1132. if (isset($result['type'])) {
  1133. if (in_array($result['type'], $this->parent_of)) {
  1134. if (class_exists($result['type'])) {
  1135. $obj = new $result['type'];
  1136. unset($result['type']);
  1137. }
  1138. }
  1139. }
  1140. $this->_dump_lock = true;
  1141. if (is_array($result)) {
  1142. foreach($result as $k => $r) {
  1143. if (!is_numeric($k)) {
  1144. $obj->$k = stripslashes($r);
  1145. }
  1146. }
  1147. }
  1148. $this->_dump_lock = false;
  1149. return $obj;
  1150. }
  1151. /**
  1152. * Iguala los valores de un resultado de la base de datos
  1153. * con sus correspondientes atributos de la clase
  1154. *
  1155. * @param array $result
  1156. * @return ActiveRecord
  1157. */
  1158. public function dump_result_self($result)
  1159. {
  1160. $this->_dump_lock = true;
  1161. if (is_array($result)) {
  1162. foreach($result as $k => $r) {
  1163. if (!is_numeric($k)) {
  1164. $this->$k = stripslashes($r);
  1165. }
  1166. }
  1167. }
  1168. $this->_dump_lock = false;
  1169. }
  1170. /**
  1171. * Crea un nuevo registro utilizando los datos del $_REQUEST
  1172. *
  1173. * @param string $form, equivalente a $_REQUEST[$form]
  1174. * @return boolean success
  1175. */
  1176. public function create_from_request($form = null)
  1177. {
  1178. if(!$form){
  1179. $form = $this->source;
  1180. }
  1181. $result = $this->create($_REQUEST[$form]);
  1182. if(!$result) {
  1183. Dispatcher::get_controller()->$form = $_REQUEST[$form];
  1184. }
  1185. return $result;
  1186. }
  1187. /**
  1188. * Saves a new Row using values from $_REQUEST
  1189. *
  1190. * @param string $form form name for request, equivalent to $_REQUEST[$form]
  1191. * @return boolean success
  1192. */
  1193. public function save_from_request($form = null)
  1194. {
  1195. if(!$form){
  1196. $form = $this->source;
  1197. }
  1198. $result = $this->save($_REQUEST[$form]);
  1199. if(!$result) {
  1200. Dispatcher::get_controller()->$form = $_REQUEST[$form];
  1201. }
  1202. return $result;
  1203. }
  1204. /**
  1205. * Updates a Row using values from $_REQUEST
  1206. *
  1207. * @param string $form form name for request, equivalent to $_REQUEST[$form]
  1208. * @return boolean success
  1209. */
  1210. public function update_from_request($form = null)
  1211. {
  1212. if(!$form){
  1213. $form = $this->source;
  1214. }
  1215. $result = $this->update($_REQUEST[$form]);
  1216. if(!$result) {
  1217. Dispatcher::get_controller()->$form = $_REQUEST[$form];
  1218. }
  1219. return $result;
  1220. }
  1221. /**
  1222. * Creates a new Row in map table
  1223. *
  1224. * @param mixed $values
  1225. * @return success boolean
  1226. */
  1227. public function create()
  1228. {
  1229. if (func_num_args() > 0) {
  1230. $params = Util::getParams(func_get_args());
  1231. $values = (isset($params[0]) && is_array($params[0])) ? $params[0] : $params;
  1232. foreach($this->fields as $field) {
  1233. if (isset($values[$field])) {
  1234. $this->$field = $values[$field];
  1235. }
  1236. }
  1237. }
  1238. if ($this->primary_key[0] == 'id') {
  1239. $this->id = null;
  1240. }
  1241. return $this->save();
  1242. }
  1243. /**
  1244. * Consulta si un determinado registro existe o no
  1245. * en la entidad de la base de datos
  1246. *
  1247. * @return boolean
  1248. */
  1249. function exists($where_pk = '')
  1250. {
  1251. if ($this->schema) {
  1252. $table = "{$this->schema}.{$this->source}";
  1253. } else {
  1254. $table = $this->source;
  1255. }
  1256. if (!$where_pk) {
  1257. $where_pk = array();
  1258. foreach($this->primary_key as $key) {
  1259. if ($this->$key) {
  1260. $where_pk[] = " $key = '{$this->$key}'";
  1261. }
  1262. }
  1263. if (count($where_pk)) {
  1264. $this->_where_pk = join(" AND ", $where_pk);
  1265. } else {
  1266. return 0;
  1267. }
  1268. $query = "SELECT COUNT(*) FROM $table WHERE {$this->_where_pk}";
  1269. } else {
  1270. if (is_numeric($where_pk)) {
  1271. $query = "SELECT(*) FROM $table WHERE id = '$where_pk'";
  1272. } else {
  1273. $query = "SELECT COUNT(*) FROM $table WHERE $where_pk";
  1274. }
  1275. }
  1276. $num = $this->db->fetch_one($query);
  1277. return $num[0];
  1278. }
  1279. /**
  1280. * Saves Information on the ActiveRecord Properties
  1281. * @param array $values array de valores a cargar
  1282. * @return boolean success
  1283. */
  1284. public function save($values=null)
  1285. {
  1286. if ($values) {
  1287. if(!is_array($values))
  1288. $values = Util::getParams(func_get_args());
  1289. foreach($this->fields as $field) {
  1290. if (isset($values[$field])) {
  1291. $this->$field = $values[$field];
  1292. }
  1293. }
  1294. }
  1295. $ex = $this->exists();
  1296. if ($this->schema) {
  1297. $table = $this->schema . "." . $this->source;
  1298. } else {
  1299. $table = $this->source;
  1300. }
  1301. #Run Validation Callbacks Before
  1302. if (method_exists($this, 'before_validation')) {
  1303. if ($this->before_validation() == 'cancel') {
  1304. return false;
  1305. }
  1306. } else {
  1307. if (isset($this->before_validation)) {
  1308. $method = $this->before_validation;
  1309. if ($this->$method() == 'cancel') {
  1310. return false;
  1311. }
  1312. }
  1313. }
  1314. if(!$ex){
  1315. if (method_exists($this, "before_validation_on_create")) {
  1316. if ($this->before_validation_on_create() == 'cancel') {
  1317. return false;
  1318. }
  1319. } else {
  1320. if (isset($this->before_validation_on_create)) {
  1321. $method = $this->before_validation_on_create;
  1322. if ($this->$method() == 'cancel') {
  1323. return false;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. if($ex){
  1329. if (method_exists($this, "before_validation_on_update")) {
  1330. if ($this->before_validation_on_update() == 'cancel') {
  1331. return false;
  1332. }
  1333. } else {
  1334. if (isset($this->before_validation_on_update)) {
  1335. $method = $this->before_validation_on_update;
  1336. if($this->$method() == 'cancel') {
  1337. return false;
  1338. }
  1339. }
  1340. }
  1341. }
  1342. /**
  1343. * Validacion validates_presence
  1344. *
  1345. */
  1346. if(isset($this->_validates['presence_of'])) {
  1347. foreach($this->_validates['presence_of'] as $f => $opt) {
  1348. if (isset($this->$f) && (is_null($this->$f) || $this->$f == '')) {
  1349. if (!$ex && $f == 'id')
  1350. continue;
  1351. if (isset($opt['message'])) {
  1352. Flash::error($opt['message']);
  1353. return false;
  1354. } else {
  1355. $field = isset($opt['field']) ? $opt['field'] : $f;
  1356. Flash::error("Error: El campo $field no puede ser nulo");
  1357. return false;
  1358. }
  1359. }
  1360. }
  1361. }
  1362. /**
  1363. * Recordamos que aqui no aparecen los que tienen valores por defecto,
  1364. * pero sin embargo se debe estar pendiente de validar en las otras verificaciones
  1365. * los campos nulos, ya que en estas si el campo es nulo, realmente se refiere a un campo que
  1366. * debe tomar el valor por defecto
  1367. *
  1368. */
  1369. foreach ($this->not_null as $f) {
  1370. if(in_array($f, $this->_with_default)) {
  1371. continue;
  1372. }
  1373. if (!isset($this->$f) || is_null($this->$f) || $this->$f == '') {
  1374. if (!$ex && $f == 'id') {
  1375. continue;
  1376. }
  1377. if (!$ex && in_array($f, $this->_at)) {
  1378. continue;
  1379. }
  1380. if ($ex && in_array($f, $this->_in)) {
  1381. continue;
  1382. }
  1383. Flash::error("Error: El campo $f no puede ser nulo");
  1384. return false;
  1385. }
  1386. }
  1387. /**
  1388. * Validacion validates_length
  1389. *
  1390. */
  1391. if(isset($this->_validates['length_of'])) {
  1392. foreach($this->_validates['length_of'] as $f => $opt) {
  1393. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1394. $field = isset($opt['field']) ? $opt['field'] : $f;
  1395. if (strlen($this->$f) < $opt['min']) {
  1396. if (isset($opt['too_short']))
  1397. Flash::error($opt['too_short']);
  1398. else
  1399. Flash::error("Error: El campo $field debe tener como mínimo $opt[min] caracteres");
  1400. return false;
  1401. }
  1402. if (strlen($this->$f) > $opt['max']) {
  1403. if (isset($opt['too_long']))
  1404. Flash::error($opt['too_long']);
  1405. else
  1406. Flash::error("Error: El campo $field debe tener como máximo $opt[max] caracteres");
  1407. return false;
  1408. }
  1409. }
  1410. }
  1411. }
  1412. /**
  1413. * Validacion validates_inclusion
  1414. *
  1415. */
  1416. foreach($this->_validates['inclusion_in'] as $f => $opt) {
  1417. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1418. if (!in_array($this->$f, $opt['list'])) {
  1419. if (isset($opt['message'])) {
  1420. Flash::error($opt['message']);
  1421. } else {
  1422. $field = isset($opt['field']) ? $opt['field'] : $f;
  1423. Flash::error("$field debe tener un valor entre (" . join(",", $opt['list']) . ")");
  1424. }
  1425. return false;
  1426. }
  1427. }
  1428. }
  1429. /**
  1430. * Validacion validates_exclusion
  1431. *
  1432. */
  1433. foreach($this->_validates['exclusion_of'] as $f => $opt) {
  1434. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1435. if (in_array($this->$f, $opt['list'])) {
  1436. if (isset($opt['message'])) {
  1437. Flash::error($opt['message']);
  1438. } else {
  1439. $field = isset($opt['field']) ? $opt['field'] : $f;
  1440. Flash::error("$field no debe tener un valor entre (" . join(",", $opt['list']) . ")");
  1441. }
  1442. return false;
  1443. }
  1444. }
  1445. }
  1446. /**
  1447. * Validacion validates_numericality
  1448. *
  1449. */
  1450. foreach($this->_validates['numericality_of'] as $f => $opt) {
  1451. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1452. if (!is_numeric($this->$f)) {
  1453. if (isset($opt['message'])) {
  1454. Flash::error($opt['message']);
  1455. } else {
  1456. $field = isset($opt['field']) ? $opt['field'] : $f;
  1457. Flash::error("$field debe tener un valor numérico");
  1458. }
  1459. return false;
  1460. }
  1461. }
  1462. }
  1463. /**
  1464. * Validacion validates_format
  1465. *
  1466. */
  1467. foreach($this->_validates['format_of'] as $f => $opt) {
  1468. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1469. if (!filter_var($this->$f, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>$opt['pattern'])))) {
  1470. if (isset($opt['message'])) {
  1471. Flash::error($opt['message']);
  1472. } else {
  1473. $field = isset($opt['field']) ? $opt['field'] : $f;
  1474. Flash::error("Formato erroneo para $field");
  1475. }
  1476. return false;
  1477. }
  1478. }
  1479. }
  1480. /**
  1481. * Validacion validates_date
  1482. *
  1483. */
  1484. foreach($this->_validates['date_in'] as $f => $opt) {
  1485. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1486. 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])$/")))) {
  1487. if (isset($opt['message'])) {
  1488. Flash::error($opt['message']);
  1489. } else {
  1490. $field = isset($opt['field']) ? $opt['field'] : $f;
  1491. Flash::error("Formato de fecha erroneo para $field");
  1492. }
  1493. return false;
  1494. }
  1495. }
  1496. }
  1497. /**
  1498. * Validacion validates_email
  1499. *
  1500. */
  1501. foreach($this->_validates['email_in'] as $f=>$opt) {
  1502. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1503. if (!filter_var($this->$f, FILTER_VALIDATE_EMAIL)) {
  1504. if (isset($opt['message'])) {
  1505. Flash::error($opt['message']);
  1506. } else {
  1507. $field = isset($opt['field']) ? $opt['field'] : $f;
  1508. Flash::error("Formato de e-mail erroneo en el campo $field");
  1509. }
  1510. return false;
  1511. }
  1512. }
  1513. }
  1514. /**
  1515. * Validacion validates_uniqueness
  1516. *
  1517. */
  1518. foreach($this->_validates['uniqueness_of'] as $f => $opt) {
  1519. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1520. $result = $this->db->fetch_one("SELECT COUNT(*) FROM $table WHERE $f = {$this->db->add_quotes($this->$f)}");
  1521. if ($result[0]) {
  1522. if (isset($opt['message'])) {
  1523. Flash::error($opt['message']);
  1524. } else {
  1525. $field = isset($opt['field']) ? $opt['field'] : $f;
  1526. Flash::error("El valor '{$this->$f}' ya existe para el campo $field");
  1527. }
  1528. return false;
  1529. }
  1530. }
  1531. }
  1532. #Run Validation Callbacks After
  1533. if(!$ex){
  1534. if (method_exists($this, "after_validation_on_create")) {
  1535. if ($this->after_validation_on_create() == 'cancel') {
  1536. return false;
  1537. }
  1538. } else {
  1539. if (isset($this->after_validation_on_create)) {
  1540. $method = $this->after_validation_on_create;
  1541. if ($this->$method() == 'cancel') {
  1542. return false;
  1543. }
  1544. }
  1545. }
  1546. }
  1547. if($ex){
  1548. if (method_exists($this, "after_validation_on_update")) {
  1549. if ($this->after_validation_on_update() == 'cancel') {
  1550. return false;
  1551. }
  1552. } else {
  1553. if (isset($this->after_validation_on_update)) {
  1554. $method = $this->after_validation_on_update;
  1555. if ($this->$method() == 'cancel') return false;
  1556. }
  1557. }
  1558. }
  1559. if (method_exists($this, 'after_validation')) {
  1560. if ($this->after_validation() == 'cancel') {
  1561. return false;
  1562. }
  1563. } else {
  1564. if (isset($this->after_validation)) {
  1565. $method = $this->after_validation;
  1566. if ($this->$method() == 'cancel') {
  1567. return false;
  1568. }
  1569. }
  1570. }
  1571. # Run Before Callbacks
  1572. if (method_exists($this, "before_save")) {
  1573. if ($this->before_save() == 'cancel') {
  1574. return false;
  1575. }
  1576. } else {
  1577. if (isset($this->before_save)) {
  1578. $method = $this->before_save;
  1579. if ($this->$method() == 'cancel') {
  1580. return false;
  1581. }
  1582. }
  1583. }
  1584. if($ex){
  1585. if (method_exists($this, "before_update")) {
  1586. if ($this->before_update() == 'cancel') {
  1587. return false;
  1588. }
  1589. } else {
  1590. if (isset($this->before_update)) {
  1591. $method = $this->before_update;
  1592. if ($this->$method() == 'cancel') {
  1593. return false;
  1594. }
  1595. }
  1596. }
  1597. }
  1598. if(!$ex){
  1599. if (method_exists($this, "before_create")) {
  1600. if ($this->before_create() == 'cancel') {
  1601. return false;
  1602. }
  1603. } else {
  1604. if (isset($this->before_create)) {
  1605. $method = $this->before_create;
  1606. if ($this->$method() == 'cancel') {
  1607. return false;
  1608. }
  1609. }
  1610. }
  1611. }
  1612. $environment = Config::read('databases');
  1613. $config = $environment[$this->get_database()];
  1614. if ($ex) {
  1615. $fields = array();
  1616. $values = array();
  1617. foreach($this->non_primary as $np) {
  1618. $np = ActiveRecord::sql_item_sanizite($np);
  1619. if (in_array($np, $this->_in)) {
  1620. if ($config['type'] == 'oracle') {
  1621. $this->$np = date("Y-m-d");
  1622. } else {
  1623. $this->$np = date("Y-m-d G:i:s");
  1624. }
  1625. }
  1626. if (isset($this->$np)) {
  1627. $fields[] = $np;
  1628. if (is_null($this->$np) || $this->$np == '') {
  1629. $values[] = "NULL";
  1630. } elseif (substr($this->$np, 0, 1) == "%") {
  1631. $values[] = str_replace("%", '', $this->$np);
  1632. } else {
  1633. /**
  1634. * Se debe especificar el formato de fecha en Oracle
  1635. */
  1636. if ($this->_data_type[$np] == 'date' && $config['type'] == 'oracle') {
  1637. $values[] = "TO_DATE(" . $this->db->add_quotes($this->$np) . ", 'YYYY-MM-DD')";
  1638. } else {
  1639. $values[] = $this->db->add_quotes($this->$np);
  1640. }
  1641. }
  1642. }
  1643. }
  1644. $val = $this->db->update($table, $fields, $values, $this->_where_pk);
  1645. } else {
  1646. $fields = array();
  1647. $values = array();
  1648. foreach($this->fields as $field) {
  1649. if ($field != 'id' && !$this->id) {
  1650. if (in_array($field, $this->_at)) {
  1651. if ($config['type'] == 'oracle') {
  1652. $this->$field = date("Y-m-d");
  1653. } else {
  1654. $this->$field = date("Y-m-d G:i:s");
  1655. }
  1656. }
  1657. if (in_array($field, $this->_in)) {
  1658. unset($this->$field);
  1659. }
  1660. $use_default = in_array($field, $this->_with_default) && isset($this->$field) && (is_null($this->$field) || $this->$field == '');
  1661. if($this->_data_type[$field] == 'datetime' || $this->_data_type[$field] == 'date' && $config['type'] == 'mysql'){
  1662. $this->$field = date("Y-m-d G:i:s",strtotime($this->$field));
  1663. }
  1664. if (isset($this->$field) && !$use_default) {
  1665. $fields[] = ActiveRecord::sql_sanizite($field);
  1666. if (substr($this->$field, 0, 1) == "%") {
  1667. $values[] = str_replace("%", '', $this->$field);
  1668. } else {
  1669. if ($this->is_a_numeric_type($field) || $this->$field == null) {
  1670. $values[] = addslashes($this->$field !== '' && $this->$field !== null ? $this->$field : "NULL");
  1671. } else {
  1672. if ($this->_data_type[$field] == 'date' && $config['type'] == 'oracle') {
  1673. /**
  1674. * Se debe especificar el formato de fecha en Oracle
  1675. */
  1676. $values[] = "TO_DATE(" . $this->db->add_quotes($this->$field) . ", 'YYYY-MM-DD')";
  1677. } else {
  1678. if (!is_null($this->$field) && $this->$field != '') {
  1679. $values[] = $this->db->add_quotes($this->$field);
  1680. } else {
  1681. $values[] = "NULL";
  1682. }
  1683. }
  1684. }
  1685. }
  1686. }
  1687. } else {
  1688. /**
  1689. * Campos autonumericos en Oracle deben utilizar una sequencia auxiliar
  1690. */
  1691. if ($config['type'] == 'oracle') {
  1692. if (!$this->id) {
  1693. $fields[] = "id";
  1694. $values[] = $this->source . "_id_seq.NEXTVAL";
  1695. }
  1696. }
  1697. if ($config['type'] == 'informix') {
  1698. if (!$this->id) {
  1699. $fields[] = "id";
  1700. $values[] = 0;
  1701. }
  1702. }
  1703. }
  1704. }
  1705. $val = $this->db->insert($table, $values, $fields);
  1706. }
  1707. if (!isset($config['pdo']) && $config['type'] == 'oracle') {
  1708. $this->commit();
  1709. }
  1710. if (!$ex) {
  1711. //$this->db->logger = true;
  1712. $m = $this->db->last_insert_id($table, $this->primary_key[0]);
  1713. $this->find_first($m);
  1714. }
  1715. if ($val) {
  1716. if($ex){
  1717. if (method_exists($this, "after_update")) {
  1718. if ($this->after_update() == 'cancel') {
  1719. return false;
  1720. }
  1721. } else {
  1722. if (isset($this->after_update)) {
  1723. $method = $this->after_update;
  1724. if ($this->$method() == 'cancel') {
  1725. return false;
  1726. }
  1727. }
  1728. }
  1729. }
  1730. if(!$ex){
  1731. if (method_exists($this, "after_create")) {
  1732. if ($this->after_create() == 'cancel') {
  1733. return false;
  1734. }
  1735. } else {
  1736. if (isset($this->after_create)) {
  1737. $method = $this->after_create;
  1738. if ($this->$method() == 'cancel') {
  1739. return false;
  1740. }
  1741. }
  1742. }
  1743. }
  1744. if (method_exists($this, "after_save")) {
  1745. if ($this->after_save() == 'cancel') {
  1746. return false;
  1747. }
  1748. } else {
  1749. if (isset($this->after_save)) {
  1750. $method = $this->after_save;
  1751. if ($this->$method() == 'cancel') {
  1752. return false;
  1753. }
  1754. }
  1755. }
  1756. return $val;
  1757. } else {
  1758. return false;
  1759. }
  1760. }
  1761. /**
  1762. * Find All data in the Relational Table
  1763. *
  1764. * @param string $field
  1765. * @param string $value
  1766. * @return ActiveRecod Cursor
  1767. */
  1768. function find_all_by($field, $value)
  1769. {
  1770. ActiveRecord::sql_item_sanizite($field);
  1771. return $this->find("conditions: $field = {$this->db->add_quotes($value) }");
  1772. }
  1773. /**
  1774. * Updates Data in the Relational Table
  1775. *
  1776. * @param mixed $values
  1777. * @return boolean sucess
  1778. */
  1779. function update()
  1780. {
  1781. if (func_num_args() > 0) {
  1782. $params = Util::getParams(func_get_args());
  1783. $values = (isset($params[0]) && is_array($params[0])) ? $params[0] : $params;
  1784. foreach($this->fields as $field) {
  1785. if (isset($values[$field])) {
  1786. $this->$field = $values[$field];
  1787. }
  1788. }
  1789. }
  1790. if ($this->exists()) {
  1791. if (method_exists($this, 'before_change')) {
  1792. $obj = clone $this;
  1793. if($this->before_change($obj->find($this->id)) == 'cancel'){
  1794. return false;
  1795. }
  1796. unset($obj);
  1797. }
  1798. if($this->save()){
  1799. if (method_exists($this, 'after_change')) {
  1800. if ($this->after_change($this) == 'cancel') {
  1801. return false;
  1802. }
  1803. }
  1804. return true;
  1805. }
  1806. } else {
  1807. Flash::error('No se puede actualizar porque el registro no existe');
  1808. return false;
  1809. }
  1810. }
  1811. /**
  1812. * Deletes data from Relational Map Table
  1813. *
  1814. * @param mixed $what
  1815. */
  1816. public function delete($what = '')
  1817. {
  1818. if (func_num_args() > 1) {
  1819. $what = Util::getParams(func_get_args());
  1820. }
  1821. if ($this->schema) {
  1822. $table = $this->schema . "." . $this->source;
  1823. } else {
  1824. $table = $this->source;
  1825. }
  1826. $conditions = '';
  1827. if (is_array($what)) {
  1828. if ($what["conditions"]) {
  1829. $conditions = $what["conditions"];
  1830. }
  1831. } else {
  1832. if (is_numeric($what)) {
  1833. ActiveRecord::sql_sanizite($this->primary_key[0]);
  1834. $conditions = "{$this->primary_key[0]} = '$what'";
  1835. } else {
  1836. if ($what) {
  1837. $conditions = $what;
  1838. } else {
  1839. ActiveRecord::sql_sanizite($this->primary_key[0]);
  1840. $conditions = "{$this->primary_key[0]} = '{$this->{$this->primary_key[0]}}'";
  1841. }
  1842. }
  1843. }
  1844. if (method_exists($this, "before_delete")) {
  1845. if ($this->id) {
  1846. $this->find($this->id);
  1847. }
  1848. if ($this->before_delete() == 'cancel') {
  1849. return false;
  1850. }
  1851. } else {
  1852. if (isset($this->before_delete)) {
  1853. if ($this->id) {
  1854. $this->find($this->id);
  1855. }
  1856. $method = $this->before_delete;
  1857. if ($this->$method() == 'cancel') {
  1858. return false;
  1859. }
  1860. }
  1861. }
  1862. $val = $this->db->delete($table, $conditions);
  1863. if ($val) {
  1864. if (method_exists($this, "after_delete")) {
  1865. if ($this->after_delete() == 'cancel') {
  1866. return false;
  1867. }
  1868. } else {
  1869. if (isset($this->after_delete)) {
  1870. $method = $this->after_delete;
  1871. if ($this->$method() == 'cancel') {
  1872. return false;
  1873. }
  1874. }
  1875. }
  1876. }
  1877. return $val;
  1878. }
  1879. /**
  1880. * Actualiza todos los atributos de la entidad
  1881. * $Clientes->update_all("estado='A', fecha='2005-02-02'", "id>100");
  1882. * $Clientes->update_all("estado='A', fecha='2005-02-02'", "id>100", "limit: 10");
  1883. *
  1884. * @param string $values
  1885. */
  1886. public function update_all($values) {
  1887. $params = array();
  1888. if ($this->schema) {
  1889. $table = $this->schema . "." . $this->source;
  1890. } else {
  1891. $table = $this->source;
  1892. }
  1893. if (func_num_args() > 1) {
  1894. $params = Util::getParams(func_get_args());
  1895. }
  1896. if (!isset($params['conditions']) || !$params['conditions']) {
  1897. if (isset($params[1])) {
  1898. $params['conditions'] = $params[1];
  1899. } else {
  1900. $params['conditions'] = '';
  1901. }
  1902. }
  1903. if ($params['conditions']) {
  1904. $params['conditions'] = " WHERE " . $params['conditions'];
  1905. }
  1906. $sql = "UPDATE $table SET $values {$params['conditions']}";
  1907. $limit_args = array($sql);
  1908. if (isset($params['limit'])) {
  1909. array_push($limit_args, "limit: $params[limit]");
  1910. }
  1911. if (isset($params['offset'])) {
  1912. array_push($limit_args, "offset: $params[offset]");
  1913. }
  1914. if (count($limit_args) > 1) {
  1915. $sql = call_user_func_array(array($this, 'limit'), $limit_args);
  1916. }
  1917. $environment = Config::read('databases');
  1918. $config = $environment[$this->get_database()];
  1919. if (!isset($config->pdo) || !$config->pdo) {
  1920. if ($config['type'] == "informix") {
  1921. $this->db->set_return_rows(false);
  1922. }
  1923. }
  1924. return $this->db->query($sql);
  1925. }
  1926. /**
  1927. * Delete All data from Relational Map Table
  1928. *
  1929. * @param string $conditions
  1930. * @return boolean
  1931. */
  1932. public function delete_all($conditions = '') {
  1933. $limit = '';
  1934. if ($this->schema) {
  1935. $table = $this->schema . "." . $this->source;
  1936. } else {
  1937. $table = $this->source;
  1938. }
  1939. if (func_num_args() > 1) {
  1940. $params = Util::getParams(func_get_args());
  1941. $limit_args = array($select);
  1942. if (isset($params['limit'])) {
  1943. array_push($limit_args, "limit: $params[limit]");
  1944. }
  1945. if (isset($params['offset'])) {
  1946. array_push($limit_args, "offset: $params[offset]");
  1947. }
  1948. if (count($limit_args) > 1) {
  1949. $select = call_user_func_array(array($this, 'limit'), $limit_args);
  1950. }
  1951. }
  1952. return $this->db->delete($table, $conditions);
  1953. }
  1954. /**
  1955. * *********************************************************************************
  1956. * Metodos de Debug
  1957. * *********************************************************************************
  1958. */
  1959. /**
  1960. * Imprime una version humana de los valores de los campos
  1961. * del modelo en una sola linea
  1962. *
  1963. */
  1964. public function inspect() {
  1965. $inspect = array();
  1966. foreach($this->fields as $field) {
  1967. if (!is_array($field)) {
  1968. $inspect[] = "$field: {$this->$field}";
  1969. }
  1970. }
  1971. return join(", ", $inspect);
  1972. }
  1973. /**
  1974. * *********************************************************************************
  1975. * Metodos de Validacion
  1976. * *********************************************************************************
  1977. */
  1978. /**
  1979. * Valida que el campo no sea nulo
  1980. *
  1981. * @param string $field campo a validar
  1982. * @param array $params parametros adicionales
  1983. *
  1984. * message: mensaje a mostrar
  1985. * field: nombre de campo a mostrar en el mensaje
  1986. */
  1987. protected function validates_presence_of($field, $params=array())
  1988. {
  1989. if (is_string($params))
  1990. $params = Util::getParams(func_get_args());
  1991. $this->_validates['presence_of'][$field] = $params;
  1992. }
  1993. /**
  1994. * Valida el tamañoo de ciertos campos antes de insertar
  1995. * o actualizar
  1996. *
  1997. * @params string $field campo a validar
  1998. * @param int $max valor maximo
  1999. * @param int $min valor minimo
  2000. * @param array $params parametros adicionales
  2001. *
  2002. * too_short: mensaje a mostrar cuando se muy corto
  2003. * too_long: mensaje a mostrar cuando sea muy largo
  2004. * field: nombre de campo a mostrar en el mensaje
  2005. */
  2006. protected function validates_length_of($field, $max, $min=0, $params=array())
  2007. {
  2008. if (is_string($params))
  2009. $params = Util::getParams(func_get_args());
  2010. $this->_validates['length_of'][$field] = $params;
  2011. $this->_validates['length_of'][$field]['min'] = $min;
  2012. $this->_validates['length_of'][$field]['max'] = $max;
  2013. }
  2014. /**
  2015. * Valida que el campo se encuentre entre los valores de una lista
  2016. * antes de insertar o actualizar
  2017. *
  2018. * @param string $field campo a validar
  2019. * @param array $list
  2020. *
  2021. * message: mensaje a mostrar
  2022. * field: nombre del campo a mostrar en el mensaje
  2023. */
  2024. protected function validates_inclusion_in($field, $list, $params=array())
  2025. {
  2026. if (is_string($params))
  2027. $params = Util::getParams(func_get_args());
  2028. $this->_validates['inclusion_in'][$field] = $params;
  2029. $this->_validates['inclusion_in'][$field]['list'] = $list;
  2030. }
  2031. /**
  2032. * Valida que el campo no se encuentre entre los valores de una lista
  2033. * antes de insertar o actualizar
  2034. *
  2035. * @param string $field campo a validar
  2036. * @param array $list
  2037. *
  2038. * message: mensaje a mostrar
  2039. * field: nombre del campo a mostrar en el mensaje
  2040. */
  2041. protected function validates_exclusion_of($field, $list, $params=array())
  2042. {
  2043. if (is_string($params))
  2044. $params = Util::getParams(func_get_args());
  2045. $this->_validates['exclusion_of'][$field] = $params;
  2046. $this->_validates['exclusion_of'][$field]['list'] = $list;
  2047. }
  2048. /**
  2049. * Valida que el campo tenga determinado formato segun una expresion regular
  2050. * antes de insertar o actualizar
  2051. *
  2052. * @param string $field campo a validar
  2053. * @param string $pattern expresion regular para preg_match
  2054. *
  2055. * message: mensaje a mostrar
  2056. * field: nombre del campo a mostrar en el mensaje
  2057. */
  2058. protected function validates_format_of($field, $pattern, $params=array())
  2059. {
  2060. if (is_string($params))
  2061. $params = Util::getParams(func_get_args());
  2062. $this->_validates['format_of'][$field] = $params;
  2063. $this->_validates['format_of'][$field]['pattern'] = $pattern;
  2064. }
  2065. /**
  2066. * Valida que ciertos atributos tengan un valor numerico
  2067. * antes de insertar o actualizar
  2068. *
  2069. * @param string $field campo a validar
  2070. *
  2071. * message: mensaje a mostrar
  2072. * field: nombre del campo a mostrar en el mensaje
  2073. */
  2074. protected function validates_numericality_of($field, $params=array())
  2075. {
  2076. if (is_string($params))
  2077. $params = Util::getParams(func_get_args());
  2078. $this->_validates['numericality_of'][$field] = $params;
  2079. }
  2080. /**
  2081. * Valida que ciertos atributos tengan un formato de e-mail correcto
  2082. * antes de insertar o actualizar
  2083. *
  2084. * @param string $field campo a validar
  2085. *
  2086. * message: mensaje a mostrar
  2087. * field: nombre del campo a mostrar en el mensaje
  2088. */
  2089. protected function validates_email_in($field, $params=array())
  2090. {
  2091. if (is_string($params))
  2092. $params = Util::getParams(func_get_args());
  2093. $this->_validates['email_in'][$field] = $params;
  2094. }
  2095. /**
  2096. * Valida que ciertos atributos tengan un valor unico antes
  2097. * de insertar o actualizar
  2098. *
  2099. * @param string $field campo a validar
  2100. *
  2101. * message: mensaje a mostrar
  2102. * field: nombre del campo a mostrar en el mensaje
  2103. */
  2104. protected function validates_uniqueness_of($field, $params=array())
  2105. {
  2106. if (is_string($params))
  2107. $params = Util::getParams(func_get_args());
  2108. $this->_validates['uniqueness_of'][$field] = $params;
  2109. }
  2110. /**
  2111. * Valida que ciertos atributos tengan un formato de fecha acorde al indicado en
  2112. * config/config.ini antes de insertar o actualizar
  2113. *
  2114. * @param string $field campo a validar
  2115. *
  2116. * message: mensaje a mostrar
  2117. * field: nombre del campo a mostrar en el mensaje
  2118. */
  2119. protected function validates_date_in($field, $params=array())
  2120. {
  2121. if (is_string($params))
  2122. $params = Util::getParams(func_get_args());
  2123. $this->_validates['date_in'][$field] = $params;
  2124. }
  2125. /**
  2126. * Verifica si un campo es de tipo de dato numerico o no
  2127. *
  2128. * @param string $field
  2129. * @return boolean
  2130. */
  2131. public function is_a_numeric_type($field)
  2132. {
  2133. if (strpos(" " . $this->_data_type[$field], "int") || strpos(" " . $this->_data_type[$field], "decimal") || strpos(" " . $this->_data_type[$field], "number")) {
  2134. return true;
  2135. } else {
  2136. return false;
  2137. }
  2138. }
  2139. /**
  2140. * Obtiene los datos de los metadatos generados por Primera vez en la Sesi&oacute;n
  2141. *
  2142. * @param string $table
  2143. * @return array
  2144. */
  2145. static function get_meta_data($table)
  2146. {
  2147. if (isset(self::$models[$table])) {
  2148. return self::$models[$table];
  2149. } elseif(PRODUCTION) {
  2150. $metadata = Cache::driver()->get($table, 'kumbia.models');
  2151. if($metadata) {
  2152. self::$models[$table] = unserialize($metadata);
  2153. return $metadata;
  2154. }
  2155. }
  2156. return array();
  2157. }
  2158. /**
  2159. * Crea un registro de meta datos para la tabla especificada
  2160. *
  2161. * @param string $table
  2162. * @param array $meta_data
  2163. */
  2164. static function set_meta_data($table, $meta_data)
  2165. {
  2166. if(PRODUCTION) {
  2167. Cache::driver()->save(serialize($meta_data), Config::get('config.application.metadata_lifetime'), $table, 'kumbia.models');
  2168. }
  2169. self::$models[$table] = $meta_data;
  2170. return true;
  2171. }
  2172. /*******************************************************************************************
  2173. * Metodos para generacion de relaciones
  2174. *******************************************************************************************/
  2175. /**
  2176. * Crea una relacion 1-1 entre dos modelos
  2177. *
  2178. * @param string $relation
  2179. *
  2180. * model : nombre del modelo al que se refiere
  2181. * fk : campo por el cual se relaciona (llave foranea)
  2182. */
  2183. protected function has_one($relation)
  2184. {
  2185. $params = Util::getParams(func_get_args());
  2186. for ($i = 0;isset($params[$i]);$i++) {
  2187. $relation = Util::uncamelize($params[$i]);
  2188. if (!array_key_exists($relation, $this->_has_one)) {
  2189. $this->_has_one[$relation] = new stdClass();
  2190. $this->_has_one[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
  2191. $this->_has_one[$relation]->fk = isset($params['fk']) ? $params['fk'] : Util::uncamelize(get_class($this)) . '_id';
  2192. }
  2193. }
  2194. }
  2195. /**
  2196. * Crea una relacion 1-1 inversa entre dos modelos
  2197. *
  2198. * @param string $relation
  2199. *
  2200. * model : nombre del modelo al que se refiere
  2201. * fk : campo por el cual se relaciona (llave foranea)
  2202. */
  2203. protected function belongs_to($relation)
  2204. {
  2205. $params = Util::getParams(func_get_args());
  2206. for ($i = 0;isset($params[$i]);$i++) {
  2207. $relation = Util::uncamelize($params[$i]);
  2208. if (!array_key_exists($relation, $this->_belongs_to)) {
  2209. $this->_belongs_to[$relation] = new stdClass();
  2210. $this->_belongs_to[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
  2211. $this->_belongs_to[$relation]->fk = isset($params['fk']) ? $params['fk'] : "{$relation}_id";
  2212. }
  2213. }
  2214. }
  2215. /**
  2216. * Crea una relacion 1-n entre dos modelos
  2217. *
  2218. * @param string $relation
  2219. *
  2220. * model : nombre del modelo al que se refiere
  2221. * fk : campo por el cual se relaciona (llave foranea)
  2222. */
  2223. protected function has_many($relation)
  2224. {
  2225. $params = Util::getParams(func_get_args());
  2226. for ($i = 0;isset($params[$i]);$i++) {
  2227. $relation = Util::uncamelize($params[$i]);
  2228. if (!array_key_exists($relation, $this->_has_many)) {
  2229. $this->_has_many[$relation] = new stdClass();
  2230. $this->_has_many[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
  2231. $this->_has_many[$relation]->fk = isset($params['fk']) ? $params['fk'] : Util::uncamelize(get_class($this)) . '_id';
  2232. }
  2233. }
  2234. }
  2235. /**
  2236. * Crea una relacion n-n o 1-n inversa entre dos modelos
  2237. *
  2238. * @param string $relation
  2239. *
  2240. * model : nombre del modelo al que se refiere
  2241. * fk : campo por el cual se relaciona (llave foranea)
  2242. * key: campo llave que identifica al propio modelo
  2243. * through : atrav�s de que tabla
  2244. */
  2245. protected function has_and_belongs_to_many($relation)
  2246. {
  2247. $params = Util::getParams(func_get_args());
  2248. for ($i = 0;isset($params[$i]);$i++) {
  2249. $relation = Util::uncamelize($params[$i]);
  2250. if (!array_key_exists($relation, $this->_has_and_belongs_to_many)) {
  2251. $this->_has_and_belongs_to_many[$relation] = new stdClass();
  2252. $this->_has_and_belongs_to_many[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
  2253. $this->_has_and_belongs_to_many[$relation]->fk = isset($params['fk']) ? $params['fk'] : "{$relation}_id";
  2254. $this->_has_and_belongs_to_many[$relation]->key = isset($params['key']) ? $params['key'] : Util::uncamelize(get_class($this)) . '_id';
  2255. if (isset($params['through'])) {
  2256. $this->_has_and_belongs_to_many[$relation]->through = $params['through'];
  2257. }
  2258. }
  2259. }
  2260. }
  2261. /**
  2262. * Herencia Simple
  2263. */
  2264. /**
  2265. * Especifica que la clase es padre de otra
  2266. *
  2267. * @param string $parent
  2268. */
  2269. public function parent_of($parent)
  2270. {
  2271. $parents = func_get_args();
  2272. foreach($parents as $parent) {
  2273. if (!in_array($parent, $this->parent_of)) {
  2274. $this->parent_of[] = $parent;
  2275. }
  2276. }
  2277. }
  2278. /**
  2279. * Elimina caracteres que podrian ayudar a ejecutar
  2280. * un ataque de Inyeccion SQL
  2281. *
  2282. * @param string $sql_item
  2283. */
  2284. public static function sql_item_sanizite($sql_item)
  2285. {
  2286. $sql_item = trim($sql_item);
  2287. if ($sql_item !== '' && $sql_item !== null) {
  2288. $sql_item = preg_replace('/\s+/', '', $sql_item);
  2289. if (!preg_match('/^[a-zA-Z0-9_\.]+$/', $sql_item)) {
  2290. throw new KumbiaException("Se esta tratando de ejecutar una operacion maliciosa!");
  2291. }
  2292. }
  2293. return $sql_item;
  2294. }
  2295. /**
  2296. * Elimina caracteres que podrian ayudar a ejecutar
  2297. * un ataque de Inyeccion SQL
  2298. *
  2299. * @param string $sql_item
  2300. */
  2301. public static function sql_sanizite($sql_item)
  2302. {
  2303. $sql_item = trim($sql_item);
  2304. if ($sql_item !== '' && $sql_item !== null) {
  2305. $sql_item = preg_replace('/\s+/', '', $sql_item);
  2306. if (!preg_match('/^[a-zA-Z_0-9\,\(\)\.\*]+$/', $sql_item)) {
  2307. throw new KumbiaException("Se esta tratando de ejecutar una operacion maliciosa!");
  2308. }
  2309. }
  2310. return $sql_item;
  2311. }
  2312. /**
  2313. * Al sobreescribir este metodo se puede controlar las excepciones de un modelo
  2314. *
  2315. * @param unknown_type $e
  2316. */
  2317. protected function exceptions($e)
  2318. {
  2319. throw $e;
  2320. }
  2321. /**
  2322. * Implementacion de __toString Standard
  2323. *
  2324. */
  2325. public function __toString()
  2326. {
  2327. return "<" . get_class() . " Object>";
  2328. }
  2329. /**
  2330. * Paginador para el modelo
  2331. *
  2332. * conditions: condiciones para paginacion
  2333. * page: numero de pagina a mostrar (por defecto la pagina 1)
  2334. * per_page: cantidad de elementos por pagina (por defecto 10 items por pagina)
  2335. *
  2336. * @return un objeto Page identico al que se regresa con el util paginate
  2337. *
  2338. */
  2339. public function paginate()
  2340. {
  2341. $args = func_get_args();
  2342. array_unshift($args, $this);
  2343. //if(!class_exists('Paginator')){
  2344. require_once CORE_PATH . 'libs/kumbia_active_record/behaviors/paginate.php';
  2345. //}
  2346. return call_user_func_array(array('Paginator' , 'paginate'), $args);
  2347. }
  2348. /**
  2349. * Paginador para el modelo atraves de consulta sql
  2350. *
  2351. * @param string $sql consulta sql
  2352. *
  2353. * page: numero de pagina a mostrar (por defecto la pagina 1)
  2354. * per_page: cantidad de elementos por pagina (por defecto 10 items por pagina)
  2355. *
  2356. * @return un objeto Page identico al que se regresa con el util paginate_by_sql
  2357. *
  2358. */
  2359. public function paginate_by_sql($sql)
  2360. {
  2361. $args = func_get_args();
  2362. array_unshift($args, $this);
  2363. //if(!class_exists('Paginator')){
  2364. require_once CORE_PATH . 'libs/kumbia_active_record/behaviors/paginate.php';
  2365. //}
  2366. return call_user_func_array(array('Paginator' , 'paginate_by_sql'), $args);
  2367. }
  2368. /**
  2369. * Operaciones al serializar
  2370. *
  2371. **/
  2372. public function __sleep()
  2373. {
  2374. /**
  2375. * Anulando conexion a bd en el modelo
  2376. **/
  2377. $this->db = null;
  2378. return array_keys(get_object_vars($this));
  2379. }
  2380. /**
  2381. * Operaciones al deserializar
  2382. *
  2383. **/
  2384. public function __wakeup()
  2385. {
  2386. /**
  2387. * Restableciendo conexion a la bd
  2388. **/
  2389. $this->_connect();
  2390. }
  2391. /**
  2392. * Obtiene la instacia de un modelo
  2393. *
  2394. * @param string $model
  2395. * @return ActiveRecord
  2396. * @throw KumbiaException
  2397. **/
  2398. public static function get($model)
  2399. {
  2400. if(isset(self::$_models[$model])) {
  2401. return self::$_models[$model];
  2402. }
  2403. /**
  2404. * Nombre de la clase
  2405. **/
  2406. $Model = Util::camelcase(basename($model));
  2407. /**
  2408. * Verifico si esta cargada la clase
  2409. **/
  2410. if(!class_exists($Model, false)) {
  2411. /**
  2412. * Carga la clase
  2413. **/
  2414. $file = APP_PATH . "models/$model.php";
  2415. if(is_file($file)) {
  2416. include $file;
  2417. } else {
  2418. throw new KumbiaException(null, 'no_model');
  2419. }
  2420. }
  2421. self::$_models[$model] = $obj = new $Model();
  2422. return $obj;
  2423. }
  2424. /**
  2425. * Devuelve un JSON de este modelo
  2426. *
  2427. * @return string JSON del modelo
  2428. */
  2429. public function to_json()
  2430. {
  2431. return json_encode($this);
  2432. }
  2433. /**
  2434. * Devuelve un array de este modelo
  2435. *
  2436. * @return array Array del modelo
  2437. */
  2438. public function to_array()
  2439. {
  2440. return ((array) $this);
  2441. }
  2442. /**
  2443. * Devuelve un PHP serial de este modelo
  2444. * Usarlo con cuidado, ya que pasa todos los atributos, no sólo los publicos
  2445. *
  2446. * @return string Serial de PHP del modelo
  2447. */
  2448. public function serialize()
  2449. {
  2450. return serialize($this);
  2451. }
  2452. }