PageRenderTime 78ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 1ms

/core/libs/kumbia_active_record/kumbia_active_record.php

http://github.com/KumbiaPHP/KumbiaPHP
PHP | 2547 lines | 1543 code | 147 blank | 857 comment | 488 complexity | 443d59e1c2a65f1d1712a47d53534fc0 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  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.
  9. *
  10. * @category Kumbia
  11. * @package ActiveRecord
  12. *
  13. * @copyright Copyright (c) 2005 - 2020 KumbiaPHP Team (http://www.kumbiaphp.com)
  14. * @license https://github.com/KumbiaPHP/KumbiaPHP/blob/master/LICENSE New BSD License
  15. */
  16. /**
  17. * @see Db
  18. */
  19. require CORE_PATH.'libs/db/db.php';
  20. /**
  21. * ActiveRecordBase Clase para el Mapeo Objeto Relacional.
  22. *
  23. * Active Record es un enfoque al problema de acceder a los datos de una
  24. * base de datos en forma orientada a objetos. Una fila en la
  25. * tabla de la base de datos (o vista) se envuelve en una clase,
  26. * de manera que se asocian filas &uacute;nicas de la base de datos
  27. * con objetos del lenguaje de programaci&oacute;n usado.
  28. * Cuando se crea uno de estos objetos, se a&ntilde;de una fila a
  29. * la tabla de la base de datos. Cuando se modifican los atributos del
  30. * objeto, se actualiza la fila de la base de datos.
  31. *
  32. * Propiedades Soportadas:
  33. * $db = Conexion al Motor de Base de datos
  34. * $database = Base de datos a la que se conecta, especificada en databases.ini
  35. * $source = Tabla que contiene la tabla que esta siendo mapeada
  36. * $fields = Listado de Campos de la tabla que han sido mapeados
  37. * $count = Conteo del ultimo Resultado de un Select
  38. * $primary_key = Listado de columnas que conforman la llave primaria
  39. * $non_primary = Listado de columnas que no son llave primaria
  40. * $not_null = Listado de campos que son not_null
  41. * $attributes_names = nombres de todos los campos que han sido mapeados
  42. * $debug = Indica si se deben mostrar los SQL enviados al RDBM en pantalla
  43. * $logger = Si es diferente de false crea un log utilizando la clase Logger
  44. * en library/kumbia/logger/logger.php, esta crea un archivo .txt en logs/ con todas las
  45. * operaciones realizadas en ActiveRecord, si $logger = "nombre", crea un
  46. * archivo con ese nombre
  47. *
  48. * Propiedades sin Soportar:
  49. * $dynamic_update : La idea es que en un futuro ActiveRecord solo
  50. * actualize los campos que han cambiado. (En Desarrollo)
  51. * $dynamic_insert : Indica si los valores del insert son solo aquellos
  52. * que sean no nulos. (En Desarrollo)
  53. * $select_before_update: Exige realizar una sentencia SELECT anterior
  54. * a la actualizacion UPDATE para comprobar que los datos no hayan sido
  55. * cambiados (En Desarrollo)
  56. * $subselect : Permitira crear una entidad ActiveRecord de solo lectura que
  57. * mapearia los resultados de un select directamente a un Objeto (En Desarrollo)
  58. *
  59. * @category Kumbia
  60. */
  61. class KumbiaActiveRecord
  62. {
  63. //Soportados
  64. /**
  65. * Resource de conexion a la base de datos.
  66. *
  67. * @var DbBase
  68. */
  69. protected $db;
  70. /**
  71. * Base de datos a la que se conecta.
  72. *
  73. * @var string
  74. */
  75. protected $database;
  76. /**
  77. * Schema donde esta la tabla.
  78. *
  79. * @var string
  80. */
  81. protected $schema;
  82. /**
  83. * Tabla utilizada para realizar el mapeo.
  84. *
  85. * @var string
  86. */
  87. protected $source;
  88. /**
  89. * Numero de resultados generados en la ultima consulta.
  90. *
  91. * @var int
  92. */
  93. protected $count;
  94. /**
  95. * Nombres de los atributos de la entidad.
  96. *
  97. * @var array
  98. */
  99. protected $fields = array();
  100. /**
  101. * LLaves primarias de la entidad.
  102. *
  103. * @var array
  104. */
  105. protected $primary_key = array();
  106. /**
  107. * Campos que no son llave primaria.
  108. *
  109. * @var array
  110. */
  111. protected $non_primary = array();
  112. /**
  113. * Campos que no permiten nulos.
  114. *
  115. * @var array
  116. */
  117. protected $not_null = array();
  118. /**
  119. * Campos que tienen valor por defecto.
  120. *
  121. * @var array
  122. */
  123. protected $_with_default = array();
  124. /**
  125. * Nombres de atributos, es lo mismo que fields.
  126. *
  127. * @var array
  128. */
  129. protected $alias = array();
  130. /**
  131. * Indica si la clase corresponde a un mapeo de una vista
  132. * en la base de datos.
  133. *
  134. * @var bool
  135. */
  136. protected $is_view = false;
  137. /**
  138. * Indica si el modelo esta en modo debug.
  139. *
  140. * @var bool
  141. */
  142. protected $debug = false;
  143. /**
  144. * Indica si se logearan los mensajes generados por la clase.
  145. *
  146. * @var mixed
  147. */
  148. protected $logger = false;
  149. /**
  150. * Indica si los datos del modelo deben ser persistidos.
  151. *
  152. * @var bool
  153. */
  154. protected $persistent = false;
  155. /**
  156. * Validaciones.
  157. *
  158. * inclusion_in: el campo pertenece a un conjunto de elementos
  159. * exclusion_of: el campo no pertenece a un conjunto de elementos
  160. * numericality_of: el campo debe ser númerico
  161. * format_of: el campo debe coincidir con la expresión regular
  162. * date_in: el campo debe ser una fecha válida
  163. * email_in: el campo debe ser un correo electrónico
  164. * uniqueness_of: el campo debe ser único
  165. *
  166. * @var array
  167. * */
  168. protected $_validates = array('inclusion_in' => array(), 'exclusion_of' => array(), 'numericality_of' => array(),
  169. 'format_of' => array(), 'date_in' => array(), 'email_in' => array(), 'uniqueness_of' => array(), );
  170. /**
  171. * Campos que terminan en _in.
  172. *
  173. * @var array
  174. */
  175. protected $_in = array();
  176. /**
  177. * Campos que terminan en _at.
  178. *
  179. * @var array
  180. */
  181. protected $_at = array();
  182. /**
  183. * Variable para crear una condicion basada en los
  184. * valores del where.
  185. *
  186. * @var string
  187. */
  188. protected $_where_pk;
  189. /**
  190. * Indica si ya se han obtenido los metadatos del Modelo.
  191. *
  192. * @var bool
  193. */
  194. protected $_dumped = false;
  195. /**
  196. * Indica si hay bloqueo sobre los warnings cuando una propiedad
  197. * del modelo no esta definida-.
  198. *
  199. * @var bool
  200. */
  201. protected $_dump_lock = false;
  202. /**
  203. * Tipos de datos de los campos del modelo.
  204. *
  205. * @var array
  206. */
  207. protected $_data_type = array();
  208. /**
  209. * Relaciones a las cuales tiene una cardinalidad 1-1.
  210. *
  211. * @var array
  212. */
  213. protected $_has_one = array();
  214. /**
  215. * Relaciones a las cuales tiene una cardinalidad 1-n.
  216. *
  217. * @var array
  218. */
  219. protected $_has_many = array();
  220. /**
  221. * Relaciones a las cuales tiene una cardinalidad 1-1.
  222. *
  223. * @var array
  224. */
  225. protected $_belongs_to = array();
  226. /**
  227. * Relaciones a las cuales tiene una cardinalidad n-n (muchos a muchos) o 1-n inversa.
  228. *
  229. * @var array
  230. */
  231. protected $_has_and_belongs_to_many = array();
  232. /**
  233. * Clases de las cuales es padre la clase actual.
  234. *
  235. * @var array
  236. */
  237. protected $parent_of = array();
  238. /**
  239. * Persistance Models Meta-data.
  240. */
  241. protected static $models = array();
  242. /**
  243. * Constructor del Modelo.
  244. *
  245. * @param array $data
  246. */
  247. public function __construct($data = null)
  248. {
  249. $this->_model_name();
  250. /*
  251. * Inicializa el modelo en caso de que exista initialize
  252. */
  253. if (method_exists($this, 'initialize')) {
  254. $this->initialize();
  255. }
  256. /*
  257. * Conecta a la bd
  258. * */
  259. $this->_connect();
  260. if ($data) {
  261. if (!is_array($data)) {
  262. $data = Util::getParams(func_get_args());
  263. }
  264. foreach ($this->fields as $field) {
  265. if (isset($data[$field])) {
  266. $this->$field = $data[$field];
  267. }
  268. }
  269. }
  270. }
  271. /**
  272. * Obtiene el nombre de la relacion en el RDBM a partir del nombre de la clase.
  273. */
  274. protected function _model_name()
  275. {
  276. if (!$this->source) {
  277. $this->source = Util::smallcase(get_class($this));
  278. }
  279. }
  280. /**
  281. * Establece publicamente el $source de la tabla.
  282. *
  283. * @param string $source
  284. */
  285. public function set_source($source)
  286. {
  287. $this->source = $source;
  288. }
  289. /**
  290. * Devuelve el source actual.
  291. *
  292. * @return string
  293. */
  294. public function get_source()
  295. {
  296. return $this->source;
  297. }
  298. /**
  299. * Establece la base datos a utilizar.
  300. *
  301. * @param string $database
  302. */
  303. public function set_database($database)
  304. {
  305. $this->database = $database;
  306. }
  307. /**
  308. * Devuelve la base de datos.
  309. *
  310. * @return string
  311. */
  312. public function get_database()
  313. {
  314. return $this->database ?: Config::read('config')['application']['database'];
  315. }
  316. /**
  317. * Pregunta si el ActiveRecord ya ha consultado la información de metadatos
  318. * de la base de datos o del registro persistente.
  319. *
  320. * @return bool
  321. */
  322. public function is_dumped()
  323. {
  324. return $this->_dumped;
  325. }
  326. /**
  327. * Devuelve los registros del modelo al que se está asociado.
  328. *
  329. * @param string $relmodel nombre del modelo asociado
  330. *
  331. * @return array|null|false si existen datos devolverá un array,
  332. * NULL si no hay datos asociados aun, y false si no existe ninguna asociación
  333. */
  334. protected function _get_relation_data($relmodel)
  335. {
  336. if (isset($this->_belongs_to[$relmodel])) {
  337. $relation = $this->_belongs_to[$relmodel];
  338. return (new $relation->model())->find_first($this->{$relation->fk});
  339. }
  340. if (isset($this->_has_one[$relmodel])) {
  341. $relation = $this->_has_one[$relmodel];
  342. if ($this->{$this->primary_key[0]}) {
  343. return (new $relation->model())->find_first("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
  344. }
  345. return null;
  346. }
  347. if (isset($this->_has_many[$relmodel])) {
  348. $relation = $this->_has_many[$relmodel];
  349. if ($this->{$this->primary_key[0]}) {
  350. return (new $relation->model())->find("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
  351. }
  352. return array();
  353. }
  354. if (isset($this->_has_and_belongs_to_many[$relmodel])) {
  355. $relation = $this->_has_and_belongs_to_many[$relmodel];
  356. $relation_model = self::get($relation->model);
  357. $source = ($this->schema ? "{$this->schema}." : null).$this->source;
  358. $relation_source = ($relation_model->schema ? "{$relation_model->schema}." : null).$relation_model->source;
  359. /*
  360. * Cargo atraves de que tabla se efectuara la relacion
  361. *
  362. */
  363. if (!isset($relation->through)) {
  364. if ($source > $relation_source) {
  365. $relation->through = "{$this->source}_{$relation_source}";
  366. } else {
  367. $relation->through = "{$relation_source}_{$this->source}";
  368. }
  369. } else {
  370. $through = explode('/', $relation->through);
  371. $relation->through = end($through);
  372. }
  373. if ($this->{$this->primary_key[0]}) {
  374. return $relation_model->find_all_by_sql("SELECT $relation_source.* FROM $relation_source, {$relation->through}, $source
  375. WHERE {$relation->through}.{$relation->key} = {$this->db->add_quotes($this->{$this->primary_key[0]}) }
  376. AND {$relation->through}.{$relation->fk} = $relation_source.{$relation_model->primary_key[0]}
  377. AND {$relation->through}.{$relation->key} = $source.{$this->primary_key[0]}
  378. ORDER BY $relation_source.{$relation_model->primary_key[0]}");
  379. }
  380. return array();
  381. }
  382. return false; //si no existe ninguna asociación devuelve false.
  383. }
  384. /**
  385. * Valida que los valores que sean leidos del objeto ActiveRecord esten definidos
  386. * previamente o sean atributos de la entidad.
  387. *
  388. * @param string $property
  389. */
  390. public function __get($property)
  391. {
  392. if (!$this->_dump_lock) {
  393. if (!isset($this->$property)) {
  394. return $this->_get_relation_data($property);
  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. public function __set($property, $value)
  407. {
  408. if (!$this->_dump_lock) {
  409. if (is_object($value) && is_subclass_of($value, 'KumbiaActiveRecord')) {
  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. return;
  415. } elseif (array_key_exists($property, $this->_has_one)) {
  416. $relation = $this->_has_one[$property];
  417. $value->{$relation->fk} = $this->{$this->primary_key[0]};
  418. return;
  419. }
  420. } elseif ($property == 'source') {
  421. $value = self::sql_item_sanitize($value);
  422. }
  423. }
  424. $this->$property = $value;
  425. }
  426. /**
  427. * Devuelve un valor o un listado dependiendo del tipo de Relación.
  428. */
  429. public function __call($method, $args = array())
  430. {
  431. if (substr($method, 0, 8) == 'find_by_') {
  432. $field = substr($method, 8);
  433. self::sql_item_sanitize($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. self::sql_item_sanitize($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. self::sql_item_sanitize($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::smallcase($model);
  466. if (($data = $this->_get_relation_data($mmodel)) !== false) {
  467. return $data;
  468. }
  469. if (method_exists($this, $method)) {
  470. call_user_func_array(array($this, $method), $args);
  471. } else {
  472. throw new KumbiaException("No existe el método '$method' en ActiveRecord::".get_class($this));
  473. }
  474. return $this->$method($args);
  475. }
  476. /**
  477. * Se conecta a la base de datos y descarga los meta-datos si es necesario.
  478. */
  479. protected function _connect()
  480. {
  481. if (!is_object($this->db)) {
  482. $this->db = Db::factory($this->database);
  483. }
  484. $this->db->debug = $this->debug;
  485. $this->db->logger = $this->logger;
  486. $this->dump();
  487. }
  488. /**
  489. * Cargar los metadatos de la tabla.
  490. */
  491. public function dump_model()
  492. {
  493. $this->_connect();
  494. }
  495. /**
  496. * Verifica si la tabla definida en $this->source existe
  497. * en la base de datos y la vuelca en dump_info.
  498. *
  499. * @return bool
  500. */
  501. protected function dump()
  502. {
  503. if ($this->_dumped) {
  504. return false;
  505. }
  506. if ($this->source) {
  507. $this->source = str_replace(';', '', strtolower($this->source));
  508. } else {
  509. $this->_model_name();
  510. if (!$this->source) {
  511. return false;
  512. }
  513. }
  514. $table = $this->source;
  515. $schema = $this->schema;
  516. if (!count(self::get_meta_data($this->source))) {
  517. $this->_dumped = true;
  518. $this->_dump_info($table, $schema);
  519. if (!count($this->primary_key)) {
  520. if (!$this->is_view) {
  521. throw new KumbiaException("No se ha definido una llave primaria para la tabla '$table' esto imposibilita crear el ActiveRecord para esta entidad");
  522. }
  523. }
  524. } else {
  525. if (!$this->is_dumped()) {
  526. $this->_dumped = true;
  527. $this->_dump_info($table, $schema);
  528. }
  529. }
  530. return true;
  531. }
  532. /**
  533. * Vuelca la informaci&oacute;n de la tabla $table en la base de datos
  534. * para armar los atributos y meta-data del ActiveRecord.
  535. *
  536. * @param string $table
  537. *
  538. * @return bool
  539. */
  540. protected function _dump_info($table, $schema = '')
  541. {
  542. $this->_dump_lock = true;
  543. if (!count(self::get_meta_data($table))) {
  544. $meta_data = $this->db->describe_table($table, $schema);
  545. if ($meta_data) {
  546. self::set_meta_data($table, $meta_data);
  547. }
  548. }
  549. foreach (self::get_meta_data($table) as $field) {
  550. $this->fields[] = $field['Field'];
  551. $aliasAux = $field['Field'];
  552. if ($field['Key'] === 'PRI') {
  553. $this->primary_key[] = $field['Field'];
  554. $this->alias[$field['Field']] = 'Código';
  555. } else {
  556. $this->non_primary[] = $field['Field'];
  557. }
  558. /*
  559. * Si se indica que no puede ser nulo, pero se indica un
  560. * valor por defecto, entonces no se incluye en la lista, ya que
  561. * al colocar un valor por defecto, el campo nunca sera nulo
  562. *
  563. */
  564. if ($field['Null'] == 'NO' && !(isset($field['Default']) && $field['Default'])) {
  565. $this->not_null[] = $field['Field'];
  566. }
  567. if (isset($field['Default']) && $field['Default']) {
  568. $this->_with_default[] = $field['Field'];
  569. }
  570. if ($field['Type']) {
  571. $this->_data_type[$field['Field']] = strtolower($field['Type']);
  572. }
  573. if (substr($field['Field'], strlen($field['Field']) - 3, 3) === '_at') {
  574. $this->_at[] = $field['Field'];
  575. $aliasAux = substr($field['Field'], 0, -3);
  576. }
  577. if (substr($field['Field'], strlen($field['Field']) - 3, 3) === '_in') {
  578. $this->_in[] = $field['Field'];
  579. $aliasAux = substr($field['Field'], 0, -3);
  580. }
  581. if (substr($field['Field'], strlen($field['Field']) - 3, 3) === '_id') {
  582. $aliasAux = substr($field['Field'], 0, -3);
  583. }
  584. //humanizando el alias
  585. $this->alias[$field['Field']] = ucwords(strtr($aliasAux, '_-', ' '));
  586. }
  587. $this->_dump_lock = false;
  588. return true;
  589. }
  590. /**
  591. * Retorna un array de los campos (fields) de una tabla Humanizados.
  592. *
  593. * @param $key
  594. *
  595. * @return array
  596. */
  597. public function get_alias($key = null)
  598. {
  599. if ($key === null) {
  600. return $this->alias;
  601. }
  602. if (isset($this->alias[$key])) {
  603. return $this->alias[$key];
  604. }
  605. throw new KumbiaException("No se pudo obtener el Alias, porque el key: \"$key\" no existe.");
  606. }
  607. /**
  608. * Asigna un nuevo valor al alias dado un key.
  609. *
  610. * @param string $key
  611. * @param string $value
  612. */
  613. public function set_alias($key, $value)
  614. {
  615. if (isset($this->alias[$key])) {
  616. $this->alias[$key] = $value;
  617. }
  618. throw new KumbiaException("No se pudo asignar el nuevo valor al Alias, porque el key: \"$key\" no existe.");
  619. }
  620. /**
  621. * Commit a Transaction.
  622. *
  623. * @return success
  624. */
  625. public function commit()
  626. {
  627. return $this->db->commit();
  628. }
  629. /**
  630. * Rollback a Transaction.
  631. *
  632. * @return success
  633. */
  634. public function rollback()
  635. {
  636. return $this->db->rollback();
  637. }
  638. /**
  639. * Start a transaction in RDBM.
  640. *
  641. * @return success
  642. */
  643. public function begin()
  644. {
  645. $this->_connect(); //(true);
  646. return $this->db->begin();
  647. }
  648. /**
  649. * Find all records in this table using a SQL Statement.
  650. *
  651. * @param string $sqlQuery
  652. *
  653. * @return ActiveRecord Cursor
  654. */
  655. public function find_all_by_sql($sqlQuery)
  656. {
  657. $results = array();
  658. foreach ($this->db->fetch_all($sqlQuery) as $result) {
  659. $results[] = $this->dump_result($result);
  660. }
  661. return $results;
  662. }
  663. /**
  664. * Find a record in this table using a SQL Statement.
  665. *
  666. * @param string $sqlQuery
  667. *
  668. * @return ActiveRecord Cursor
  669. */
  670. public function find_by_sql($sqlQuery)
  671. {
  672. $row = $this->db->fetch_one($sqlQuery);
  673. if ($row !== false) {
  674. $this->dump_result_self($row);
  675. return $this->dump_result($row);
  676. } else {
  677. return false;
  678. }
  679. }
  680. /**
  681. * Execute a SQL Statement directly.
  682. *
  683. * @param string $sqlQuery
  684. *
  685. * @return int affected
  686. */
  687. public function sql($sqlQuery)
  688. {
  689. return $this->db->query($sqlQuery);
  690. }
  691. /**
  692. * Return Fist Record.
  693. *
  694. * Recibe los mismos parametros que find
  695. *
  696. * @param mixed $what
  697. *
  698. * @return ActiveRecord Cursor
  699. */
  700. public function find_first($what = '')
  701. {
  702. $what = Util::getParams(func_get_args());
  703. $select = 'SELECT ';
  704. if (isset($what['columns'])) {
  705. $select .= self::sql_sanitize($what['columns']);
  706. } elseif (isset($what['distinct'])) {
  707. $select .= 'DISTINCT ';
  708. $select .= $what['distinct'] ? self::sql_sanitize($what['distinct']) : join(',', $this->fields);
  709. } else {
  710. $select .= join(',', $this->fields);
  711. }
  712. if ($this->schema) {
  713. $select .= " FROM {$this->schema}.{$this->source}";
  714. } else {
  715. $select .= " FROM {$this->source}";
  716. }
  717. $what['limit'] = 1;
  718. $select .= $this->convert_params_to_sql($what);
  719. $resp = false;
  720. $result = $this->db->fetch_one($select);
  721. if ($result) {
  722. $this->dump_result_self($result);
  723. $resp = $this->dump_result($result);
  724. }
  725. return $resp;
  726. }
  727. /**
  728. * Find data on Relational Map table.
  729. *
  730. * @param string $what
  731. *
  732. * @return ActiveRecord Cursor
  733. *
  734. * columns: columnas a utilizar
  735. * conditions : condiciones de busqueda en WHERE
  736. * join: inclusion inner join o outer join
  737. * group : campo para grupo en GROUP BY
  738. * having : condicion para el grupo
  739. * order : campo para criterio de ordenamiento ORDER BY
  740. * distinct: campos para hacer select distinct
  741. */
  742. public function find($what = '')
  743. {
  744. $what = Util::getParams(func_get_args());
  745. $select = 'SELECT ';
  746. if (isset($what['columns'])) {
  747. $select .= $what['columns'] ? self::sql_sanitize($what['columns']) : join(',', $this->fields);
  748. } elseif (isset($what['distinct'])) {
  749. $select .= 'DISTINCT ';
  750. $select .= $what['distinct'] ? self::sql_sanitize($what['distinct']) : join(',', $this->fields);
  751. } else {
  752. $select .= join(',', $this->fields);
  753. }
  754. if ($this->schema) {
  755. $select .= " FROM {$this->schema}.{$this->source}";
  756. } else {
  757. $select .= " FROM {$this->source}";
  758. }
  759. $select .= $this->convert_params_to_sql($what);
  760. $results = array();
  761. $all_results = $this->db->in_query($select);
  762. foreach ($all_results as $result) {
  763. $results[] = $this->dump_result($result);
  764. }
  765. $this->count = count($results, COUNT_NORMAL);
  766. if (isset($what[0]) && is_numeric($what[0])) {
  767. if (!isset($results[0])) {
  768. $this->count = 0;
  769. return false;
  770. }
  771. $this->dump_result_self($all_results[0]);
  772. $this->count = 1;
  773. return $results[0];
  774. }
  775. $this->count = count($results, COUNT_NORMAL);
  776. return $results;
  777. }
  778. /*
  779. * Arma una consulta SQL con el parametro $what, así:
  780. * $what = Util::getParams(func_get_args());
  781. * $select = "SELECT * FROM Clientes";
  782. * $select.= $this->convert_params_to_sql($what);
  783. *
  784. * @param string|array $what
  785. * @return string
  786. */
  787. public function convert_params_to_sql($what = '')
  788. {
  789. $select = '';
  790. if (is_array($what)) {
  791. if (!isset($what['conditions'])) {
  792. if (!isset($this->primary_key[0]) && (isset($this->id) || $this->is_view)) {
  793. $this->primary_key[0] = 'id';
  794. }
  795. self::sql_item_sanitize($this->primary_key[0]);
  796. if (isset($what[0])) {
  797. if (is_numeric($what[0])) {
  798. $what['conditions'] = "{$this->primary_key[0]} = ".(int) $what[0];
  799. } else {
  800. if ($what[0] == '') {
  801. $what['conditions'] = "{$this->primary_key[0]} = ''";
  802. } else {
  803. $what['conditions'] = $what[0];
  804. }
  805. }
  806. }
  807. }
  808. if (isset($what['join'])) {
  809. $select .= " {$what['join']}";
  810. }
  811. if (isset($what['conditions'])) {
  812. $select .= " WHERE {$what['conditions']}";
  813. }
  814. if (isset($what['group'])) {
  815. $select .= " GROUP BY {$what['group']}";
  816. }
  817. if (isset($what['having'])) {
  818. $select .= " HAVING {$what['having']}";
  819. }
  820. if (isset($what['order'])) {
  821. self::sql_sanitize($what['order']);
  822. $select .= " ORDER BY {$what['order']}";
  823. }
  824. $limit_args = array($select);
  825. if (isset($what['limit'])) {
  826. array_push($limit_args, 'limit: '.(int) $what['limit']);
  827. }
  828. if (isset($what['offset'])) {
  829. array_push($limit_args, 'offset: '.(int) $what['offset']);
  830. }
  831. if (count($limit_args) > 1) {
  832. $select = call_user_func_array(array($this, 'limit'), $limit_args);
  833. }
  834. } else {
  835. if (strlen($what)) {
  836. if (is_numeric($what)) {
  837. $select .= "WHERE {$this->primary_key[0]} = ".(int) $what[0];
  838. } else {
  839. $select .= "WHERE $what";
  840. }
  841. }
  842. }
  843. return $select;
  844. }
  845. /*
  846. * Devuelve una clausula LIMIT adecuada al RDBMS empleado
  847. *
  848. * limit: maxima cantidad de elementos a mostrar
  849. * offset: desde que elemento se comienza a mostrar
  850. *
  851. * @param string $sql consulta select
  852. * @return String clausula LIMIT adecuada al RDBMS empleado
  853. */
  854. public function limit($sql)
  855. {
  856. $args = func_get_args();
  857. return call_user_func_array(array($this->db, 'limit'), $args);
  858. }
  859. /**
  860. * Ejecuta un SELECT DISTINCT.
  861. *
  862. * @param string $what
  863. *
  864. * @return array
  865. *
  866. * Soporta parametros iguales a find
  867. */
  868. public function distinct($what = '')
  869. {
  870. $what = Util::getParams(func_get_args());
  871. if ($this->schema) {
  872. $table = $this->schema.'.'.$this->source;
  873. } else {
  874. $table = $this->source;
  875. }
  876. if (empty($what['columns'])) {
  877. $what['columns'] = $what['0'];
  878. }
  879. $what['columns'] = self::sql_sanitize($what['columns']);
  880. $select = "SELECT DISTINCT {$what['columns']} FROM $table ";
  881. /*
  882. * Se elimina el de indice cero ya que por defecto convert_params_to_sql lo considera como una condicion en WHERE
  883. */
  884. unset($what[0]);
  885. $select .= $this->convert_params_to_sql($what);
  886. $results = array();
  887. foreach ($this->db->fetch_all($select) as $result) {
  888. $results[] = $result[0];
  889. }
  890. return $results;
  891. }
  892. /**
  893. * Ejecuta una consulta en el RDBM directamente.
  894. *
  895. * @param string $sql
  896. *
  897. * @return resource
  898. */
  899. public static function static_select_one($sql)
  900. {
  901. $db = Db::factory();
  902. if (substr(ltrim($sql), 0, 7) != 'SELECT') {
  903. $sql = 'SELECT '.$sql;
  904. }
  905. $num = $db->fetch_one($sql);
  906. return $num[0];
  907. }
  908. /**
  909. * Realiza un conteo de filas.
  910. *
  911. * @param string $what
  912. *
  913. * @return int
  914. */
  915. public function count($what = '')
  916. {
  917. $what = Util::getParams(func_get_args());
  918. if ($this->schema) {
  919. $table = "{$this->schema}.{$this->source}";
  920. } else {
  921. $table = $this->source;
  922. }
  923. unset($what['order']);
  924. if (isset($what['distinct']) && $what['distinct']) {
  925. if (isset($what['group'])) {
  926. $select = "SELECT COUNT(*) FROM (SELECT DISTINCT {$what['distinct']} FROM $table ";
  927. $select .= $this->convert_params_to_sql($what);
  928. $select .= ') AS t ';
  929. } else {
  930. $select = "SELECT COUNT(DISTINCT {$what['distinct']}) FROM $table ";
  931. $select .= $this->convert_params_to_sql($what);
  932. }
  933. } else {
  934. $select = "SELECT COUNT(*) FROM $table ";
  935. $select .= $this->convert_params_to_sql($what);
  936. }
  937. $num = $this->db->fetch_one($select);
  938. return $num[0];
  939. }
  940. /**
  941. * Realiza un promedio sobre el campo $what.
  942. *
  943. * @param string $what
  944. *
  945. * @return array
  946. */
  947. public function average($what = '')
  948. {
  949. $what = Util::getParams(func_get_args());
  950. if (isset($what['column'])) {
  951. if (!$what['column']) {
  952. $what['column'] = $what[0];
  953. }
  954. } else {
  955. $what['column'] = $what[0];
  956. }
  957. unset($what[0]);
  958. self::sql_item_sanitize($what['column']);
  959. if ($this->schema) {
  960. $table = "{$this->schema}.{$this->source}";
  961. } else {
  962. $table = $this->source;
  963. }
  964. $select = "SELECT AVG({$what['column']}) FROM $table ";
  965. $select .= $this->convert_params_to_sql($what);
  966. $num = $this->db->fetch_one($select);
  967. return $num[0];
  968. }
  969. public function sum($what = '')
  970. {
  971. $what = Util::getParams(func_get_args());
  972. if (isset($what['column'])) {
  973. if (!$what['column']) {
  974. $what['column'] = $what[0];
  975. }
  976. } else {
  977. $what['column'] = $what[0];
  978. }
  979. unset($what[0]);
  980. self::sql_item_sanitize($what['column']);
  981. if ($this->schema) {
  982. $table = "{$this->schema}.{$this->source}";
  983. } else {
  984. $table = $this->source;
  985. }
  986. $select = "SELECT SUM({$what['column']}) FROM $table ";
  987. $select .= $this->convert_params_to_sql($what);
  988. $num = $this->db->fetch_one($select);
  989. return $num[0];
  990. }
  991. /**
  992. * Busca el valor maximo para el campo $what.
  993. *
  994. * @param string $what
  995. *
  996. * @return mixed
  997. */
  998. public function maximum($what = '')
  999. {
  1000. $what = Util::getParams(func_get_args());
  1001. if (isset($what['column'])) {
  1002. if (!$what['column']) {
  1003. $what['column'] = $what[0];
  1004. }
  1005. } else {
  1006. $what['column'] = $what[0];
  1007. }
  1008. unset($what[0]);
  1009. self::sql_item_sanitize($what['column']);
  1010. if ($this->schema) {
  1011. $table = "{$this->schema}.{$this->source}";
  1012. } else {
  1013. $table = $this->source;
  1014. }
  1015. $select = "SELECT MAX({$what['column']}) FROM $table ";
  1016. $select .= $this->convert_params_to_sql($what);
  1017. $num = $this->db->fetch_one($select);
  1018. return $num[0];
  1019. }
  1020. /**
  1021. * Busca el valor minimo para el campo $what.
  1022. *
  1023. * @param string $what
  1024. *
  1025. * @return mixed
  1026. */
  1027. public function minimum($what = '')
  1028. {
  1029. $what = Util::getParams(func_get_args());
  1030. if (isset($what['column'])) {
  1031. if (!$what['column']) {
  1032. $what['column'] = $what[0];
  1033. }
  1034. } else {
  1035. $what['column'] = $what[0];
  1036. }
  1037. unset($what[0]);
  1038. self::sql_item_sanitize($what['column']);
  1039. if ($this->schema) {
  1040. $table = "{$this->schema}.{$this->source}";
  1041. } else {
  1042. $table = $this->source;
  1043. }
  1044. $select = "SELECT MIN({$what['column']}) FROM $table ";
  1045. $select .= $this->convert_params_to_sql($what);
  1046. $num = $this->db->fetch_one($select);
  1047. return $num[0];
  1048. }
  1049. /**
  1050. * Realiza un conteo directo mediante $sql.
  1051. *
  1052. * @param string $sqlQuery
  1053. *
  1054. * @return mixed
  1055. */
  1056. public function count_by_sql($sqlQuery)
  1057. {
  1058. $num = $this->db->fetch_one($sqlQuery);
  1059. return $num[0];
  1060. }
  1061. /**
  1062. * Iguala los valores de un resultado de la base de datos
  1063. * en un nuevo objeto con sus correspondientes
  1064. * atributos de la clase.
  1065. *
  1066. * @param array $result
  1067. *
  1068. * @return ActiveRecord
  1069. */
  1070. public function dump_result($result)
  1071. {
  1072. $obj = clone $this;
  1073. /*
  1074. * Consulta si la clase es padre de otra y crea el tipo de dato correcto
  1075. */
  1076. if (isset($result['type'])) {
  1077. if (in_array($result['type'], $this->parent_of)) {
  1078. if (class_exists($result['type'])) {
  1079. $obj = new $result['type']();
  1080. unset($result['type']);
  1081. }
  1082. }
  1083. }
  1084. $this->_dump_lock = true;
  1085. if (is_array($result)) {
  1086. foreach ($result as $k => $r) {
  1087. if (!is_numeric($k)) {
  1088. if (!is_object($r)) {
  1089. $obj->$k = stripslashes($r);
  1090. } else {
  1091. $obj->$k = $r->load();
  1092. }
  1093. }
  1094. }
  1095. }
  1096. $this->_dump_lock = false;
  1097. return $obj;
  1098. }
  1099. /**
  1100. * Iguala los valores de un resultado de la base de datos
  1101. * con sus correspondientes atributos de la clase.
  1102. *
  1103. * @param array $result
  1104. *
  1105. * @return ActiveRecord
  1106. */
  1107. public function dump_result_self($result)
  1108. {
  1109. $this->_dump_lock = true;
  1110. if (is_array($result)) {
  1111. foreach ($result as $k => $r) {
  1112. if (!is_numeric($k)) {
  1113. if (!is_object($r)) {
  1114. $this->$k = is_array($r) ? $r : stripslashes($r);
  1115. } else {
  1116. $this->$k = $r->load();
  1117. }
  1118. }
  1119. }
  1120. }
  1121. $this->_dump_lock = false;
  1122. }
  1123. /**
  1124. * Crea un nuevo registro utilizando los datos del $_REQUEST.
  1125. *
  1126. * @param string $form, equivalente a $_REQUEST[$form]
  1127. *
  1128. * @return bool success
  1129. *
  1130. * @deprecated No es seguro
  1131. */
  1132. public function create_from_request($form = null)
  1133. {
  1134. if (!$form) {
  1135. $form = $this->source;
  1136. }
  1137. return $this->create($_REQUEST[$form]);
  1138. }
  1139. /**
  1140. * Saves a new Row using values from $_REQUEST.
  1141. *
  1142. * @param string $form form name for request, equivalent to $_REQUEST[$form]
  1143. *
  1144. * @return bool success
  1145. *
  1146. * @deprecated No es seguro
  1147. */
  1148. public function save_from_request($form = null)
  1149. {
  1150. if (!$form) {
  1151. $form = $this->source;
  1152. }
  1153. return $this->save($_REQUEST[$form]);
  1154. }
  1155. /**
  1156. * Updates a Row using values from $_REQUEST.
  1157. *
  1158. * @param string $form form name for request, equivalent to $_REQUEST[$form]
  1159. *
  1160. * @return bool|null success
  1161. */
  1162. public function update_from_request($form = null)
  1163. {
  1164. if (!$form) {
  1165. $form = $this->source;
  1166. }
  1167. return $this->update($_REQUEST[$form]);
  1168. }
  1169. /**
  1170. * Creates a new Row in map table.
  1171. *
  1172. * @param mixed $values
  1173. *
  1174. * @return bool success
  1175. */
  1176. public function create()
  1177. {
  1178. if (func_num_args() > 0) {
  1179. $params = Util::getParams(func_get_args());
  1180. $values = (isset($params[0]) && is_array($params[0])) ? $params[0] : $params;
  1181. foreach ($this->fields as $field) {
  1182. if (isset($values[$field])) {
  1183. $this->$field = $values[$field];
  1184. }
  1185. }
  1186. }
  1187. if ($this->primary_key[0] == 'id') {
  1188. $this->id = null;
  1189. }
  1190. return $this->save();
  1191. }
  1192. /**
  1193. * Consulta si un determinado registro existe o no
  1194. * en la entidad de la base de datos.
  1195. *
  1196. * @return bool
  1197. */
  1198. public function exists($where_pk = '')
  1199. {
  1200. if ($this->schema) {
  1201. $table = "{$this->schema}.{$this->source}";
  1202. } else {
  1203. $table = $this->source;
  1204. }
  1205. if (!$where_pk) {
  1206. $where_pk = array();
  1207. foreach ($this->primary_key as $key) {
  1208. if ($this->$key) {
  1209. $where_pk[] = " $key = '{$this->$key}'";
  1210. }
  1211. }
  1212. if (count($where_pk)) {
  1213. $this->_where_pk = join(' AND ', $where_pk);
  1214. } else {
  1215. return 0;
  1216. }
  1217. $query = "SELECT COUNT(*) FROM $table WHERE {$this->_where_pk}";
  1218. } else {
  1219. if (is_numeric($where_pk)) {
  1220. $query = "SELECT COUNT(*) FROM $table WHERE {$this->primary_key[0]} = '$where_pk'";
  1221. } else {
  1222. $query = "SELECT COUNT(*) FROM $table WHERE $where_pk";
  1223. }
  1224. }
  1225. $num = $this->db->fetch_one($query);
  1226. return $num[0];
  1227. }
  1228. /**
  1229. * Saves Information on the ActiveRecord Properties.
  1230. *
  1231. * @param array $values array de valores a cargar
  1232. *
  1233. * @return bool success
  1234. */
  1235. public function save($values = null)
  1236. {
  1237. if ($values) {
  1238. if (!is_array($values)) {
  1239. $values = Util::getParams(func_get_args());
  1240. }
  1241. foreach ($this->fields as $field) {
  1242. if (isset($values[$field])) {
  1243. $this->$field = $values[$field];
  1244. }
  1245. }
  1246. }
  1247. $ex = $this->exists();
  1248. if ($this->schema) {
  1249. $table = $this->schema.'.'.$this->source;
  1250. } else {
  1251. $table = $this->source;
  1252. }
  1253. //Run Validation Callbacks Before
  1254. if (method_exists($this, 'before_validation')) {
  1255. if ($this->before_validation() == 'cancel') {
  1256. return false;
  1257. }
  1258. } else {
  1259. if (isset($this->before_validation)) {
  1260. $method = $this->before_validation;
  1261. if ($this->$method() == 'cancel') {
  1262. return false;
  1263. }
  1264. }
  1265. }
  1266. if (!$ex) {
  1267. if (method_exists($this, 'before_validation_on_create')) {
  1268. if ($this->before_validation_on_create() == 'cancel') {
  1269. return false;
  1270. }
  1271. } else {
  1272. if (isset($this->before_validation_on_create)) {
  1273. $method = $this->before_validation_on_create;
  1274. if ($this->$method() == 'cancel') {
  1275. return false;
  1276. }
  1277. }
  1278. }
  1279. }
  1280. if ($ex) {
  1281. if (method_exists($this, 'before_validation_on_update')) {
  1282. if ($this->before_validation_on_update() == 'cancel') {
  1283. return false;
  1284. }
  1285. } else {
  1286. if (isset($this->before_validation_on_update)) {
  1287. $method = $this->before_validation_on_update;
  1288. if ($this->$method() == 'cancel') {
  1289. return false;
  1290. }
  1291. }
  1292. }
  1293. }
  1294. /*
  1295. * Validacion validates_presence
  1296. *
  1297. */
  1298. if (isset($this->_validates['presence_of'])) {
  1299. foreach ($this->_validates['presence_of'] as $f => $opt) {
  1300. if (isset($this->$f) && (is_null($this->$f) || $this->$f === '')) {
  1301. if (!$ex && $f == $this->primary_key[0]) {
  1302. continue;
  1303. }
  1304. if (isset($opt['message'])) {
  1305. Flash::error($opt['message']);
  1306. return false;
  1307. } else {
  1308. $field = isset($opt['field']) ? $opt['field'] : $f;
  1309. Flash::error("Error: El campo $field no puede ser nulo");
  1310. return false;
  1311. }
  1312. }
  1313. }
  1314. }
  1315. /*
  1316. * Recordamos que aqui no aparecen los que tienen valores por defecto,
  1317. * pero sin embargo se debe estar pendiente de validar en las otras verificaciones
  1318. * los campos nulos, ya que en estas si el campo es nulo, realmente se refiere a un campo que
  1319. * debe tomar el valor por defecto
  1320. *
  1321. */
  1322. foreach ($this->not_null as $f) {
  1323. if (in_array($f, $this->_with_default)) {
  1324. continue;
  1325. }
  1326. if (!isset($this->$f) || is_null($this->$f) || $this->$f == '') {
  1327. if (!$ex && $f == $this->primary_key[0]) {
  1328. continue;
  1329. }
  1330. if (!$ex && in_array($f, $this->_at)) {
  1331. continue;
  1332. }
  1333. if ($ex && in_array($f, $this->_in)) {
  1334. continue;
  1335. }
  1336. Flash::error("Error: El campo $f no puede ser nulo");
  1337. return false;
  1338. }
  1339. }
  1340. /*
  1341. * Validacion validates_length
  1342. *
  1343. */
  1344. if (isset($this->_validates['length_of'])) {
  1345. foreach ($this->_validates['length_of'] as $f => $opt) {
  1346. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1347. $field = isset($opt['field']) ? $opt['field'] : $f;
  1348. if (strlen($this->$f) < $opt['min']) {
  1349. if (isset($opt['too_short'])) {
  1350. Flash::error($opt['too_short']);
  1351. } else {
  1352. Flash::error("Error: El campo $field debe tener como mínimo $opt[min] caracteres");
  1353. }
  1354. return false;
  1355. }
  1356. if (strlen($this->$f) > $opt['max']) {
  1357. if (isset($opt['too_long'])) {
  1358. Flash::error($opt['too_long']);
  1359. } else {
  1360. Flash::error("Error: El campo $field debe tener como máximo $opt[max] caracteres");
  1361. }
  1362. return false;
  1363. }
  1364. }
  1365. }
  1366. }
  1367. /*
  1368. * Validacion validates_inclusion
  1369. *
  1370. */
  1371. foreach ($this->_validates['inclusion_in'] as $f => $opt) {
  1372. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1373. if (!in_array($this->$f, $opt['list'])) {
  1374. if (isset($opt['message'])) {
  1375. Flash::error($opt['message']);
  1376. } else {
  1377. $field = isset($opt['field']) ? $opt['field'] : $f;
  1378. Flash::error("$field debe tener un valor entre (".join(',', $opt['list']).')');
  1379. }
  1380. return false;
  1381. }
  1382. }
  1383. }
  1384. /*
  1385. * Validacion validates_exclusion
  1386. *
  1387. */
  1388. foreach ($this->_validates['exclusion_of'] as $f => $opt) {
  1389. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1390. if (in_array($this->$f, $opt['list'])) {
  1391. if (isset($opt['message'])) {
  1392. Flash::error($opt['message']);
  1393. } else {
  1394. $field = isset($opt['field']) ? $opt['field'] : $f;
  1395. Flash::error("$field no debe tener un valor entre (".join(',', $opt['list']).')');
  1396. }
  1397. return false;
  1398. }
  1399. }
  1400. }
  1401. /*
  1402. * Validacion validates_numericality
  1403. *
  1404. */
  1405. foreach ($this->_validates['numericality_of'] as $f => $opt) {
  1406. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1407. if (!is_numeric($this->$f)) {
  1408. if (isset($opt['message'])) {
  1409. Flash::error($opt['message']);
  1410. } else {
  1411. $field = isset($opt['field']) ? $opt['field'] : $f;
  1412. Flash::error("$field debe tener un valor numérico");
  1413. }
  1414. return false;
  1415. }
  1416. }
  1417. }
  1418. /*
  1419. * Validacion validates_format
  1420. *
  1421. */
  1422. foreach ($this->_validates['format_of'] as $f => $opt) {
  1423. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1424. if (!filter_var($this->$f, FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => $opt['pattern'])))) {
  1425. if (isset($opt['message'])) {
  1426. Flash::error($opt['message']);
  1427. } else {
  1428. $field = isset($opt['field']) ? $opt['field'] : $f;
  1429. Flash::error("Formato erroneo para $field");
  1430. }
  1431. return false;
  1432. }
  1433. }
  1434. }
  1435. /*
  1436. * Validacion validates_date
  1437. *
  1438. */
  1439. foreach ($this->_validates['date_in'] as $f => $opt) {
  1440. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1441. 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])$/")))) {
  1442. if (isset($opt['message'])) {
  1443. Flash::error($opt['message']);
  1444. } else {
  1445. $field = isset($opt['field']) ? $opt['field'] : $f;
  1446. Flash::error("Formato de fecha erroneo para $field");
  1447. }
  1448. return false;
  1449. }
  1450. }
  1451. }
  1452. /*
  1453. * Validacion validates_email
  1454. *
  1455. */
  1456. foreach ($this->_validates['email_in'] as $f => $opt) {
  1457. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1458. if (!filter_var($this->$f, FILTER_VALIDATE_EMAIL)) {
  1459. if (isset($opt['message'])) {
  1460. Flash::error($opt['message']);
  1461. } else {
  1462. $field = isset($opt['field']) ? $opt['field'] : $f;
  1463. Flash::error("Formato de e-mail erroneo en el campo $field");
  1464. }
  1465. return false;
  1466. }
  1467. }
  1468. }
  1469. /**
  1470. * Validacion validates_uniqueness.
  1471. */
  1472. // parche para que no tome encuenta el propio registro
  1473. // al validar campos unicos, ya que si lo toma en cuenta
  1474. // lanzará error de validacion porque ya existe un registro
  1475. // con igual valor en el campo unico.
  1476. $and_condition = $ex ? " AND {$this->primary_key[0]} != '{$this->{$this->primary_key[0]}}'" : '';
  1477. foreach ($this->_validates['uniqueness_of'] as $f => $opt) {
  1478. if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
  1479. $result = $this->db->fetch_one("SELECT COUNT(*) FROM $table WHERE $f = {$this->db->add_quotes($this->$f)} $and_condition");
  1480. if ($result[0]) {
  1481. if (isset($opt['message'])) {
  1482. Flash::error($opt['message']);
  1483. } else {
  1484. $field = isset($opt['field']) ? $opt['field'] : $f;
  1485. Flash::error("El valor '{$this->$f}' ya existe para el campo $field");
  1486. }
  1487. return false;
  1488. }
  1489. }
  1490. }
  1491. //Run Validation Callbacks After
  1492. if (!$ex) {
  1493. if (method_exists($this, 'after_validation_on_create')) {
  1494. if ($this->after_validation_on_create() == 'cancel') {
  1495. return false;
  1496. }
  1497. } else {
  1498. if (isset($this->after_validation_on_create)) {
  1499. $method = $this->after_validation_on_create;
  1500. if ($this->$method() == 'cancel') {
  1501. return false;
  1502. }
  1503. }
  1504. }
  1505. }
  1506. if ($ex) {
  1507. if (method_exists($this, 'after_validation_on_update')) {
  1508. if ($this->after_validati

Large files files are truncated, but you can click here to view the full file