<?php
/**
* KumbiaPHP web & app Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://wiki.kumbiaphp.com/Licencia
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to hide@address.com so we can send you a copy immediately.
*
* ActiveRecordBase Clase para el Mapeo Objeto Relacional
*
* @category Kumbia
* @package Db
* @subpackage ActiveRecord
* @copyright Copyright (c) 2005-2009 Kumbia Team (http://www.kumbiaphp.com)
* @license http://wiki.kumbiaphp.com/Licencia New BSD License
*/
/**
* ActiveRecordException
*/
require_once CORE_PATH . 'libs/db/active_record_base/exception.php';
/**
* ActiveRecordBase Clase para el Mapeo Objeto Relacional
*
* Active Record es un enfoque al problema de acceder a los datos de una
* base de datos en forma orientada a objetos. Una fila en la
* tabla de la base de datos (o vista) se envuelve en una clase,
* de manera que se asocian filas únicas de la base de datos
* con objetos del lenguaje de programación usado.
* Cuando se crea uno de estos objetos, se añde una fila a
* la tabla de la base de datos. Cuando se modifican los atributos del
* objeto, se actualiza la fila de la base de datos.
*
* Propiedades Soportadas:
* $db = Conexion al Motor de Base de datos
* $database = Base de datos a la que se conecta, especificada en databases.ini
* $source = Tabla que contiene la tabla que esta siendo mapeada
* $fields = Listado de Campos de la tabla que han sido mapeados
* $count = Conteo del ultimo Resultado de un Select
* $primary_key = Listado de columnas que conforman la llave primaria
* $non_primary = Listado de columnas que no son llave primaria
* $not_null = Listado de campos que son not_null
* $attributes_names = nombres de todos los campos que han sido mapeados
* $debug = Indica si se deben mostrar los SQL enviados al RDBM en pantalla
* $logger = Si es diferente de false crea un log utilizando la clase Logger
* en library/kumbia/logger/logger.php, esta crea un archivo .txt en logs/ con todas las
* operaciones realizadas en ActiveRecord, si $logger = "nombre", crea un
* archivo con ese nombre
*
* Propiedades sin Soportar:
* $dynamic_update : La idea es que en un futuro ActiveRecord solo
* actualize los campos que han cambiado. (En Desarrollo)
* $dynamic_insert : Indica si los valores del insert son solo aquellos
* que sean no nulos. (En Desarrollo)
* $select_before_update: Exige realizar una sentencia SELECT anterior
* a la actualizacion UPDATE para comprobar que los datos no hayan sido
* cambiados (En Desarrollo)
* $subselect : Permitira crear una entidad ActiveRecord de solo lectura que
* mapearia los resultados de un select directamente a un Objeto (En Desarrollo)
*
*/
class ActiveRecordBase
{
//Soportados
/**
* Resource de conexion a la base de datos
*
* @var DbBase
*/
public $db;
/**
* Base de datos a la que se conecta
*
* @var string
*/
protected $database;
/**
* Schema donde esta la tabla
*
* @var string
*/
protected $schema;
/**
* Tabla utilizada para realizar el mapeo
*
* @var string
*/
protected $source;
/**
* Numero de resultados generados en la ultima consulta
*
* @var integer
*/
public $count;
/**
* Nombres de los atributos de la entidad
*
* @var array
*/
public $fields = array();
/**
* LLaves primarias de la entidad
*
* @var array
*/
public $primary_key = array();
/**
* Campos que no son llave primaria
*
* @var array
*/
public $non_primary = array();
/**
* Campos que no permiten nulos
*
* @var array
*/
public $not_null = array();
/**
* Campos que tienen valor por defecto
*
* @var array
*/
protected $_with_default = array();
/**
* Nombres de atributos, es lo mismo que fields
*
* @var array
*/
public $attributes_names = array();
/**
* Indica si la clase corresponde a un mapeo de una vista
* en la base de datos
*
* @var boolean
*/
public $is_view = false;
/**
* Indica si el modelo esta en modo debug
*
* @var boolean
*/
public $debug = false;
/**
* Indica si se logearan los mensajes generados por la clase
*
* @var mixed
*/
public $logger = false;
/**
* Indica si los datos del modelo deben ser persistidos
*
* @var boolean
*/
public $persistent = false;
/**
* Validaciones
*
* inclusion_in: el campo pertenece a un conjunto de elementos
* exclusion_of: el campo no pertenece a un conjunto de elementos
* numericality_of: el campo debe ser numerico
* format_of: el campo debe coincidir con la expresion regular compatible con perl
* date_in: el campo debe ser una fecha valida
* email_in: el campo debe ser un correo electronico
* uniqueness_of: el campo debe ser unico
*
* @var array
**/
protected $_validates = array('inclusion_in' => array(), 'exclusion_of' => array(), 'numericality_of' => array(),
'format_of' => array(), 'date_in' => array(), 'email_in' => array(), 'uniqueness_of' => array());
/**
* Campos que terminan en _in
*
* @var array
*/
protected $_in = array();
/**
* Campos que terminan en _at
*
* @var array
*/
protected $_at = array();
/**
* Variable para crear una condicion basada en los
* valores del where
*
* @var string
*/
protected $_where_pk;
/**
* Indica si ya se han obtenido los metadatos del Modelo
*
* @var boolean
*/
protected $_dumped = false;
/**
* Indica si hay bloqueo sobre los warnings cuando una propiedad
* del modelo no esta definida-
*
* @var boolean
*/
protected $_dump_lock = false;
/**
* Tipos de datos de los campos del modelo
*
* @var array
*/
protected $_data_type = array();
/**
* Relaciones a las cuales tiene una cardinalidad 1-1
*
* @var array
*/
protected $_has_one = array();
/**
* Relaciones a las cuales tiene una cardinalidad 1-n
*
* @var array
*/
protected $_has_many = array();
/**
* Relaciones a las cuales tiene una cardinalidad 1-1
*
* @var array
*/
protected $_belongs_to = array();
/**
* Relaciones a las cuales tiene una cardinalidad n-n (muchos a muchos) o 1-n inversa
*
* @var array
*/
protected $_has_and_belongs_to_many = array();
/**
* Clases de las cuales es padre la clase actual
*
* @var array
*/
public $parent_of = array();
/**
* Persistance Models Meta-data
*/
protected static $_models = array();
/**
* Persistance Models Meta-data
*/
public static $models = array();
/**
* Constructor del Modelo
*
* @param array $data
*/
function __construct($data=null)
{
if (!$this->source) {
$this->_model_name();
}
/**
* Inicializa el modelo en caso de que exista initialize
*/
if (method_exists($this, 'initialize')) {
$this->initialize();
}
/**
* Conecta a la bd
**/
$this->_connect();
if ($data) {
if (!is_array($data))
$data = Util::getParams(func_get_args());
$this->dump_result_self($data);
}
}
/**
* Obtiene el nombre de la relacion en el RDBM a partir del nombre de la clase
*
*/
protected function _model_name()
{
if (!$this->source) {
$this->source = Util::uncamelize(get_class($this));
}
}
/**
* Establece publicamente el $source de la tabla
*
* @param string $source
*/
public function set_source($source)
{
$this->source = $source;
}
/**
* Devuelve el source actual
*
* @return string
*/
public function get_source()
{
return $this->source;
}
/**
* Establece la base datos a utilizar
*
* @param string $databse
*/
public function set_database($database)
{
$this->database = $database;
}
/**
* Devuelve la base de datos
*
* @return string
*/
public function get_database()
{
if ($this->database) {
return $this->database;
} else {
$core = Config::read('config');
return $core['application']['database'];
}
}
/**
* Pregunta si el ActiveRecord ya ha consultado la informacion de metadatos
* de la base de datos o del registro persistente
*
* @return boolean
*/
public function is_dumped()
{
return $this->_dumped;
}
/**
* Valida que los valores que sean leidos del objeto ActiveRecord esten definidos
* previamente o sean atributos de la entidad
*
* @param string $property
*/
function __get($property)
{
if (!$this->_dump_lock) {
if (!isset($this->$property)) {
if (array_key_exists($property, $this->_belongs_to)) {
$relation = $this->_belongs_to[$property];
return self::get($relation->model)->find_first($this->{$relation->fk});
} elseif (array_key_exists($property, $this->_has_one)) {
$relation = $this->_has_one[$property];
if ($this->{$this->primary_key[0]}) {
return self::get($relation->model)->find_first("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
} else {
return null;
}
} elseif (array_key_exists($property, $this->_has_many)) {
$relation = $this->_has_many[$property];
if ($this->{$this->primary_key[0]}) {
return self::get($relation->model)->find("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
} else {
return array();
}
} elseif (array_key_exists($property, $this->_has_and_belongs_to_many)) {
$relation = $this->_has_and_belongs_to_many[$property];
$relation_model = self::get($relation->model);
$relation_model->dump_model();
$source = $this->source;
$relation_source = $relation_model->source;
/**
* Cargo atraves de que tabla se efectuara la relacion
*
*/
if (!isset($relation->through)) {
if ($source > $relation_source) {
$relation->through = "{$this->source}_{$relation_source}";
} else {
$relation->through = "{$relation_source}_{$this->source}";
}
}
if ($this->{$this->primary_key[0]}) {
return self::get($relation->model)->find_all_by_sql("SELECT $relation_source.* FROM $relation_source, {$relation->through}, $source
WHERE {$relation->through}.{$relation->key} = {$this->db->add_quotes($this->{$this->primary_key[0]}) }
AND {$relation->through}.{$relation->fk} = $relation_source.{$relation_model->primary_key[0]}
AND {$relation->through}.{$relation->key} = $source.{$this->primary_key[0]}
ORDER BY $relation_source.{$relation_model->primary_key[0]}");
} else {
return array();
}
} else {
return null;
}
}
}
return $this->$property;
}
/**
* Valida que los valores que sean asignados al objeto ActiveRecord esten definidos
* o sean atributos de la entidad
*
* @param string $property
* @param mixed $value
*/
function __set($property, $value)
{
if (!$this->_dump_lock) {
if (!isset($this->$property) && is_object($value) && is_subclass_of($value, 'ActiveRecordBase')) {
if (array_key_exists($property, $this->_belongs_to)) {
$relation = $this->_belongs_to[$property];
$value->dump_model();
$this->{$relation->fk} = $value->{$value->primary_key[0]};
} elseif (array_key_exists($property, $this->_has_one)) {
$relation = $this->_has_one[$property];
$value->{$relation->fk} = $this->{$this->primary_key[0]};
}
} elseif ($property == "source") {
$value = ActiveRecord::sql_item_sanizite($value);
}
}
$this->$property = $value;
}
/**
* Devuelve un valor o un listado dependiendo del tipo de Relación
*
*/
public function __call($method, $args = array())
{
$has_relation = false;
if (substr($method, 0, 8) == "find_by_") {
$field = substr($method, 8);
ActiveRecord::sql_item_sanizite($field);
if (isset($args[0])) {
$arg = array("conditions: $field = {$this->db->add_quotes($args[0]) }");
unset($args[0]);
} else {
$arg = array();
}
return call_user_func_array(array($this, "find_first"), array_merge($arg, $args));
}
if (substr($method, 0, 9) == "count_by_") {
$field = substr($method, 9);
ActiveRecord::sql_item_sanizite($field);
if (isset($args[0])) {
$arg = array("conditions: $field = {$this->db->add_quotes($args[0]) }");
unset($args[0]);
} else {
$arg = array();
}
return call_user_func_array(array($this, "count"), array_merge($arg, $args));
}
if (substr($method, 0, 12) == "find_all_by_") {
$field = substr($method, 12);
ActiveRecord::sql_item_sanizite($field);
if (isset($args[0])) {
$arg = array("conditions: $field = {$this->db->add_quotes($args[0]) }");
unset($args[0]);
} else {
$arg = array();
}
return call_user_func_array(array($this, "find"), array_merge($arg, $args));
}
$model = ereg_replace("^get", "", $method);
$mmodel = Util::uncamelize($model);
if (array_key_exists($mmodel, $this->_belongs_to)) {
$has_relation = true;
$relation = $this->_belongs_to[$mmodel];
return self::get($relation->model)->find_first($this->{$relation->fk});
}
if (array_key_exists($mmodel, $this->_has_many)) {
$has_relation = true;
$relation = $this->_has_many[$mmodel];
if ($this->{$this->primary_key[0]}) {
return self::get($relation->model)->find("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
} else {
return array();
}
}
if (array_key_exists($mmodel, $this->_has_one)) {
$has_relation = true;
$relation = $this->_has_one[$mmodel];
if ($this->{$this->primary_key[0]}) {
return self::get($relation->model)->find_first("{$relation->fk}={$this->db->add_quotes($this->{$this->primary_key[0]}) }");
} else {
return null;
}
}
if (array_key_exists($mmodel, $this->_has_and_belongs_to_many)) {
$has_relation = true;
$relation = $this->_has_and_belongs_to_many[$mmodel];
if ($this->{$this->primary_key[0]}) {
$source = $this->source;
$relation_model = self::get($relation->model);
$relation_model->dump_model();
$relation_source = $relation_model->source;
/**
* Cargo atraves de que tabla se efectuara la relacion
*
*/
if (!isset($relation->through)) {
if ($source > $relation_source) {
$relation->through = "{$this->source}_{$relation_source}";
} else {
$relation->through = "{$relation_source}_{$this->source}";
}
}
return self::get($relation->model)->find_all_by_sql("SELECT $relation_source.* FROM $relation_source, {$relation->through}, $source
WHERE {$relation->through}.{$relation->key} = {$this->db->add_quotes($this->{$this->primary_key[0]}) }
AND {$relation->through}.{$relation->fk} = $relation_source.{$relation_model->primary_key[0]}
AND {$relation->through}.{$relation->key} = $source.{$this->primary_key[0]}
ORDER BY $relation_source.{$relation_model->primary_key[0]}");
} else {
return array();
}
}
try {
if (method_exists($this, $method)) {
call_user_func_array(array($this, $method), $args);
} else {
if ($has_relation) {
throw new ActiveRecordException("No existe el modelo '$model' para relacionar con ActiveRecord::{$this->source}");
} else {
throw new ActiveRecordException("No existe el método '$method' en ActiveRecord::" . get_class($this));
}
}
}
catch(Exception $e) {
$this->exceptions($e);
}
return $this->$method($args);
}
/**
* Se conecta a la base de datos y descarga los meta-datos si es necesario
*
* @param boolean $new_connection
*/
protected function _connect($new_connection = false)
{
if (!is_object($this->db) || $new_connection) {
if ($this->database) {
$this->db = DbBase::raw_connect($new_connection, $this->database);
} else {
$this->db = DbBase::raw_connect($new_connection);
}
}
$this->db->debug = $this->debug;
$this->db->logger = $this->logger;
$this->dump();
}
/**
* Cargar los metadatos de la tabla
*
*/
public function dump_model()
{
$this->_connect();
}
/**
* Verifica si la tabla definida en $this->source existe
* en la base de datos y la vuelca en dump_info
*
* @return boolean
*/
protected function dump()
{
if ($this->_dumped) {
return false;
}
$a = array();
if ($this->source) {
$this->source = str_replace(";", "", strtolower($this->source));
} else {
$this->_model_name();
if (!$this->source) {
return false;
}
}
$table = $this->source;
$schema = $this->schema;
if (!count(self::get_meta_data($this->source))) {
$this->_dumped = true;
$this->_dump_info($table, $schema);
if (!count($this->primary_key)) {
if (!$this->is_view) {
throw new ActiveRecordException("No se ha definido una llave primaria para la tabla '$table' esto imposibilita crear el ActiveRecord para esta entidad");
return false;
}
}
} else {
if (!$this->is_dumped()) {
$this->_dumped = true;
$this->_dump_info($table, $schema);
}
}
return true;
}
/**
* Vuelca la información de la tabla $table en la base de datos
* para armar los atributos y meta-data del ActiveRecord
*
* @param string $table
* @return boolean
*/
protected function _dump_info($table, $schema = '')
{
$this->_dump_lock = true;
if (!count(self::get_meta_data($table))) {
$meta_data = $this->db->describe_table($table, $schema);
if ($meta_data) {
self::set_meta_data($table, $meta_data);
}
}
foreach(self::get_meta_data($table) as $field) {
$this->fields[] = $field['Field'];
if ($field['Key'] == 'PRI') {
$this->primary_key[] = $field['Field'];
} else $this->non_primary[] = $field['Field'];
/**
* Si se indica que no puede ser nulo, pero se indica un
* valor por defecto, entonces no se incluye en la lista, ya que
* al colocar un valor por defecto, el campo nunca sera nulo
*
*/
if ($field['Null'] == 'NO' && !(isset($field['Default']) && $field['Default'])) {
$this->not_null[] = $field['Field'];
}
if (isset($field['Default']) && $field['Default']) {
$this->_with_default[] = $field['Field'];
}
if ($field['Type']) {
$this->_data_type[$field['Field']] = strtolower($field['Type']);
}
if (substr($field['Field'], strlen($field['Field']) - 3, 3) == '_at') {
$this->_at[] = $field['Field'];
}
if (substr($field['Field'], strlen($field['Field']) - 3, 3) == '_in') {
$this->_in[] = $field['Field'];
}
}
$this->attributes_names = $this->fields;
$this->_dump_lock = false;
return true;
}
/**
* Commit a Transaction
*
* @return success
*/
public function commit()
{
return $this->db->commit();
}
/**
* Rollback a Transaction
*
* @return success
*/
public function rollback()
{
return $this->db->rollback();
}
/**
* Start a transaction in RDBM
*
* @return success
*/
public function begin()
{
$this->_connect(true);
return $this->db->begin();
}
/**
* Find all records in this table using a SQL Statement
*
* @param string $sqlQuery
* @return ActiveRecord Cursor
*/
public function find_all_by_sql($sqlQuery)
{
$results = array();
foreach($this->db->fetch_all($sqlQuery) as $result) {
$results[] = $this->dump_result($result);
}
return $results;
}
/**
* Find a record in this table using a SQL Statement
*
* @param string $sqlQuery
* @return ActiveRecord Cursor
*/
public function find_by_sql($sqlQuery)
{
$row = $this->db->fetch_one($sqlQuery);
if ($row !== false) {
$this->dump_result_self($row);
return $this->dump_result($row);
} else {
return false;
}
}
/**
* Execute a SQL Statement directly
*
* @param string $sqlQuery
* @return int affected
*/
public function sql($sqlQuery)
{
return $this->db->query($sqlQuery);
}
/**
* Return Fist Record
*
* @param mixed $what
* @param boolean $debug
*
* Recibe los mismos parametros que find
*
* @return ActiveRecord Cursor
*/
public function find_first($what = '')
{
$what = Util::getParams(func_get_args());
$select = "SELECT ";
if (isset($what['columns'])) {
$select.= ActiveRecord::sql_sanizite($what['columns']);
} elseif (isset($what['distinct'])) {
$select.= 'DISTINCT ';
$select.= $what['distinct'] ? ActiveRecord::sql_sanizite($what['distinct']) : join(",", $this->fields);
} else {
$select.= join(",", $this->fields);
}
if ($this->schema) {
$select.= " FROM {$this->schema}.{$this->source}";
} else {
$select.= " FROM {$this->source}";
}
$what['limit'] = 1;
$select.= $this->convert_params_to_sql($what);
$resp = false;
try {
$result = $this->db->fetch_one($select);
if ($result) {
$this->dump_result_self($result);
$resp = $this->dump_result($result);
}
}
catch(Exception $e) {
$this->exceptions($e);
}
return $resp;
}
/**
* Find data on Relational Map table
*
* @param string $what
* @return ActiveRecord Cursor
*
* columns: columnas a utilizar
* conditions : condiciones de busqueda en WHERE
* join: inclusion inner join o outer join
* group : campo para grupo en GROUP BY
* having : condicion para el grupo
* order : campo para criterio de ordenamiento ORDER BY
* distinct: campos para hacer select distinct
*/
public function find($what = '')
{
$what = Util::getParams(func_get_args());
$select = "SELECT ";
if (isset($what['columns'])) {
$select.= $what['columns'] ? ActiveRecord::sql_sanizite($what['columns']) : join(",", $this->fields);
} elseif (isset($what['distinct'])) {
$select.= 'DISTINCT ';
$select.= $what['distinct'] ? ActiveRecord::sql_sanizite($what['distinct']) : join(",", $this->fields);
} else {
$select.= join(",", $this->fields);
}
if ($this->schema) {
$select.= " FROM {$this->schema}.{$this->source}";
} else {
$select.= " FROM {$this->source}";
}
$select.= $this->convert_params_to_sql($what);
$results = array();
$all_results = $this->db->in_query($select);
foreach($all_results AS $result) {
$results[] = $this->dump_result($result);
}
$this->count = count($results);
if (isset($what[0]) && is_numeric($what[0])) {
if (!isset($results[0])) {
$this->count = 0;
return false;
} else {
$this->dump_result_self($all_results[0]);
$this->count = 1;
return $results[0];
}
} else {
$this->count = count($results);
return $results;
}
}
/*
* Arma una consulta SQL con el parametro $what, asÃ:
* $what = Util::getParams(func_get_args());
* $select = "SELECT * FROM Clientes";
* $select.= $this->convert_params_to_sql($what);
*
* @param string $what
* @return string
*/
public function convert_params_to_sql($what = '')
{
$select = "";
if (is_array($what)) {
if (!isset($what['conditions'])) {
if (!isset($this->primary_key[0]) && (isset($this->id) || $this->is_view)) {
$this->primary_key[0] = "id";
}
ActiveRecord::sql_item_sanizite($this->primary_key[0]);
if (isset($what[0])) {
if (is_numeric($what[0])) {
$what['conditions'] = "{$this->primary_key[0]} = {$this->db->add_quotes($what[0]) }";
} else {
if ($what[0] == '') {
$what['conditions'] = "{$this->primary_key[0]} = ''";
} else {
$what['conditions'] = $what[0];
}
}
}
}
if (isset($what['join']) && $what['join']) {
$select.= " {$what['join']}";
}
if (isset($what['conditions']) && $what['conditions']) {
$select.= " WHERE {$what['conditions']}";
}
if (isset($what['group']) && $what['group']) {
$select.= " GROUP BY {$what['group']}";
}
if (isset($what['having']) && $what['having']) {
$select.= " HAVING {$what['having']}";
}
if (isset($what['order']) && $what['order']) {
ActiveRecord::sql_sanizite($what['order']);
$select.= " ORDER BY {$what['order']}";
}
$limit_args = array($select);
if (isset($what['limit'])) {
array_push($limit_args, "limit: $what[limit]");
}
if (isset($what['offset'])) {
array_push($limit_args, "offset: $what[offset]");
}
if (count($limit_args) > 1) {
$select = call_user_func_array(array($this, 'limit'), $limit_args);
}
} else {
if (strlen($what)) {
if (is_numeric($what)) {
$select.= "WHERE {$this->primary_key[0]} = '$what'";
} else {
$select.= "WHERE $what";
}
}
}
return $select;
}
/*
* Devuelve una clausula LIMIT adecuada al RDBMS empleado
*
* limit: maxima cantidad de elementos a mostrar
* offset: desde que elemento se comienza a mostrar
*
* @param string $sql consulta select
* @return String clausula LIMIT adecuada al RDBMS empleado
*/
public function limit($sql)
{
$args = func_get_args();
return call_user_func_array(array($this->db, 'limit'), $args);
}
/**
* Ejecuta un SELECT DISTINCT
* @param string $what
* @return array
*
* Soporta parametros iguales a find
*
*/
public function distinct($what = '')
{
$what = Util::getParams(func_get_args());
if ($this->schema) {
$table = $this->schema . "." . $this->source;
} else {
$table = $this->source;
}
if (!isset($what['columns'])) {
$what['columns'] = $what['0'];
} else {
if (!$what['columns']) {
$what['columns'] = $what['0'];
}
}
$what['columns'] = ActiveRecord::sql_sanizite($what['columns']);
$select = "SELECT DISTINCT {$what['columns']} FROM $table ";
/**
* Se elimina el de indice cero ya que por defecto convert_params_to_sql lo considera como una condicion en WHERE
*/
unset($what[0]);
$select.= $this->convert_params_to_sql($what);
$results = array();
foreach($this->db->fetch_all($select) as $result) {
$results[] = $result[0];
}
return $results;
}
/**
* Ejecuta una consulta en el RDBM directamente
*
* @param string $sql
* @return resource
*/
public function select_one($sql)
{
if (substr(ltrim($sql), 0, 7) != "SELECT") {
$sql = "SELECT " . $sql;
}
$num = $this->db->fetch_one($sql);
return $num[0];
}
static public function static_select_one($sql)
{
$db = db::raw_connect();
if (substr(ltrim($sql), 0, 7) != "SELECT") {
$sql = "SELECT " . $sql;
}
$num = $db->fetch_one($sql);
return $num[0];
}
/**
* Realiza un conteo de filas
*
* @param string $what
* @return integer
*/
public function count($what = '')
{
$what = Util::getParams(func_get_args());
if ($this->schema) {
$table = "{$this->schema}.{$this->source}";
} else {
$table = $this->source;
}
if (isset($what['distinct']) && $what['distinct']) {
if (isset($what['group']) || isset($what['order'])) {
$select = "SELECT COUNT(*) FROM (SELECT DISTINCT {$what['distinct']} FROM $table ";
$select.= $this->convert_params_to_sql($what);
$select.= ') AS t ';
} else {
$select = "SELECT COUNT(DISTINCT {$what['distinct']}) FROM $table ";
$select.= $this->convert_params_to_sql($what);
}
} else {
$select = "SELECT COUNT(*) FROM $table ";
$select.= $this->convert_params_to_sql($what);
}
$num = $this->db->fetch_one($select);
return $num[0];
}
/**
* Realiza un promedio sobre el campo $what
*
* @param string $what
* @return array
*/
public function average($what = '')
{
$what = Util::getParams(func_get_args());
if (isset($what['column'])) {
if (!$what['column']) {
$what['column'] = $what[0];
}
} else {
$what['column'] = $what[0];
}
unset($what[0]);
ActiveRecord::sql_item_sanizite($what['column']);
if ($this->schema) {
$table = "{$this->schema}.{$this->source}";
} else {
$table = $this->source;
}
$select = "SELECT AVG({$what['column']}) FROM $table ";
$select.= $this->convert_params_to_sql($what);
$num = $this->db->fetch_one($select);
return $num[0];
}
public function sum($what = '')
{
$what = Util::getParams(func_get_args());
if (isset($what['column'])) {
if (!$what['column']) {
$what['column'] = $what[0];
}
} else {
$what['column'] = $what[0];
}
unset($what[0]);
ActiveRecord::sql_item_sanizite($what['column']);
if ($this->schema) {
$table = "{$this->schema}.{$this->source}";
} else {
$table = $this->source;
}
$select = "SELECT SUM({$what['column']}) FROM $table ";
$select.= $this->convert_params_to_sql($what);
$num = $this->db->fetch_one($select);
return $num[0];
}
/**
* Busca el valor maximo para el campo $what
*
* @param string $what
* @return mixed
*/
public function maximum($what = '')
{
$what = Util::getParams(func_get_args());
if (isset($what['column'])) {
if (!$what['column']) {
$what['column'] = $what[0];
}
} else {
$what['column'] = $what[0];
}
unset($what[0]);
ActiveRecord::sql_item_sanizite($what['column']);
if ($this->schema) {
$table = "{$this->schema}.{$this->source}";
} else {
$table = $this->source;
}
$select = "SELECT MAX({$what['column']}) FROM $table ";
$select.= $this->convert_params_to_sql($what);
$num = $this->db->fetch_one($select);
return $num[0];
}
/**
* Busca el valor minimo para el campo $what
*
* @param string $what
* @return mixed
*/
public function minimum($what = '')
{
$what = Util::getParams(func_get_args());
if (isset($what['column'])) {
if (!$what['column']) {
$what['column'] = $what[0];
}
} else {
$what['column'] = $what[0];
}
unset($what[0]);
ActiveRecord::sql_item_sanizite($what['column']);
if ($this->schema) {
$table = "{$this->schema}.{$this->source}";
} else {
$table = $this->source;
}
$select = "SELECT MIN({$what['column']}) FROM $table ";
$select.= $this->convert_params_to_sql($what);
$num = $this->db->fetch_one($select);
return $num[0];
}
/**
* Realiza un conteo directo mediante $sql
*
* @param string $sqlQuery
* @return mixed
*/
public function count_by_sql($sqlQuery)
{
$num = $this->db->fetch_one($sqlQuery);
return $num[0];
}
/**
* Iguala los valores de un resultado de la base de datos
* en un nuevo objeto con sus correspondientes
* atributos de la clase
*
* @param array $result
* @return ActiveRecord
*/
public function dump_result($result){
$obj = clone $this;
/**
* Consulta si la clase es padre de otra y crea el tipo de dato correcto
*/
if (isset($result['type'])) {
if (in_array($result['type'], $this->parent_of)) {
if (class_exists($result['type'])) {
$obj = new $result['type'];
unset($result['type']);
}
}
}
$this->_dump_lock = true;
if (is_array($result)) {
foreach($result as $k => $r) {
if (!is_numeric($k)) {
$obj->$k = stripslashes($r);
}
}
}
$this->_dump_lock = false;
return $obj;
}
/**
* Iguala los valores de un resultado de la base de datos
* con sus correspondientes atributos de la clase
*
* @param array $result
* @return ActiveRecord
*/
public function dump_result_self($result)
{
$this->_dump_lock = true;
if (is_array($result)) {
foreach($result as $k => $r) {
if (!is_numeric($k)) {
$this->$k = stripslashes($r);
}
}
}
$this->_dump_lock = false;
}
/**
* Create a new Row using values from $_REQUEST
*
* @param string $form form name for request, equivalent to $_REQUEST[$form]
* @return boolean success
*/
public function create_from_request($form = '')
{
if ($form) {
return $this->create($_REQUEST[$form]);
} else {
return $this->create($_REQUEST);
}
}
/**
* Saves a new Row using values from $_REQUEST
*
* @param string $form form name for request, equivalent to $_REQUEST[$form]
* @return boolean success
*/
public function save_from_request($form = '')
{
if ($form) {
return $this->save($_REQUEST[$form]);
} else {
return $this->save($_REQUEST);
}
}
/**
* Updates a Row using values from $_REQUEST
*
* @param string $form form name for request, equivalent to $_REQUEST[$form]
* @return boolean success
*/
public function update_from_request($form = '')
{
if ($form) {
return $this->update($_REQUEST[$form]);
} else {
return $this->update($_REQUEST);
}
}
/**
* Creates a new Row in map table
*
* @param mixed $values
* @return success boolean
*/
public function create()
{
if (func_num_args() > 0) {
$params = Util::getParams(func_get_args());
$values = (isset($params[0]) && is_array($params[0])) ? $params[0] : $params;
foreach($this->fields as $field) {
if (isset($values[$field])) {
$this->$field = $values[$field];
}
}
}
if ($this->primary_key[0] == 'id') {
$this->id = null;
}
return $this->save();
}
/**
* Consulta si un determinado registro existe o no
* en la entidad de la base de datos
*
* @return boolean
*/
function exists($where_pk = '')
{
if ($this->schema) {
$table = "{$this->schema}.{$this->source}";
} else {
$table = $this->source;
}
if (!$where_pk) {
$where_pk = array();
foreach($this->primary_key as $key) {
if ($this->$key) {
$where_pk[] = " $key = '{$this->$key}'";
}
}
if (count($where_pk)) {
$this->_where_pk = join(" AND ", $where_pk);
} else {
return 0;
}
$query = "SELECT COUNT(*) FROM $table WHERE {$this->_where_pk}";
} else {
if (is_numeric($where_pk)) {
$query = "SELECT(*) FROM $table WHERE id = '$where_pk'";
} else {
$query = "SELECT COUNT(*) FROM $table WHERE $where_pk";
}
}
$num = $this->db->fetch_one($query);
return $num[0];
}
/**
* Saves Information on the ActiveRecord Properties
* @param array $values array de valores a cargar
* @return boolean success
*/
public function save($values=null)
{
if ($values) {
if(!is_array($values))
$values = Util::getParams(func_get_args());
foreach($this->fields as $field) {
if (isset($values[$field])) {
$this->$field = $values[$field];
}
}
}
$ex = $this->exists();
if ($this->schema) {
$table = $this->schema . "." . $this->source;
} else {
$table = $this->source;
}
#Run Validation Callbacks Before
if (method_exists($this, 'before_validation')) {
if ($this->before_validation() == 'cancel') {
return false;
}
} else {
if (isset($this->before_validation)) {
$method = $this->before_validation;
if ($this->$method() == 'cancel') {
return false;
}
}
}
if(!$ex){
if (method_exists($this, "before_validation_on_create")) {
if ($this->before_validation_on_create() == 'cancel') {
return false;
}
} else {
if (isset($this->before_validation_on_create)) {
$method = $this->before_validation_on_create;
if ($this->$method() == 'cancel') {
return false;
}
}
}
}
if($ex){
if (method_exists($this, "before_validation_on_update")) {
if ($this->before_validation_on_update() == 'cancel') {
return false;
}
} else {
if (isset($this->before_validation_on_update)) {
$method = $this->before_validation_on_update;
if($this->$method() == 'cancel') {
return false;
}
}
}
}
/**
* Validacion validates_presence
*
*/
if(isset($this->_validates['presence_of'])) {
foreach($this->_validates['presence_of'] as $f => $opt) {
if (isset($this->$f) && (is_null($this->$f) || $this->$f == '')) {
if (!$ex && $f == 'id')
continue;
if (isset($opt['message'])) {
Flash::error($opt['message']);
return false;
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("Error: El campo $field no puede ser nulo");
return false;
}
}
}
}
/**
* Recordamos que aqui no aparecen los que tienen valores por defecto,
* pero sin embargo se debe estar pendiente de validar en las otras verificaciones
* los campos nulos, ya que en estas si el campo es nulo, realmente se refiere a un campo que
* debe tomar el valor por defecto
*
*/
foreach ($this->not_null as $f) {
if (!isset($this->$f) || is_null($this->$f) || $this->$f == '') {
if (!$ex && $f == 'id') {
continue;
}
if (!$ex && in_array($f, $this->_at)) {
continue;
}
if ($ex && in_array($f, $this->_in)) {
continue;
}
Flash::error("Error: El campo $f no puede ser nulo");
return false;
}
}
/**
* Validacion validates_length
*
*/
if(isset($this->_validates['length_of'])) {
foreach($this->_validates['length_of'] as $f => $opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
$field = isset($opt['field']) ? $opt['field'] : $f;
if (strlen($this->$f) < $opt['min']) {
if (isset($opt['too_short']))
Flash::error($opt['too_short']);
else
Flash::error("Error: El campo $field debe tener como mÃnimo $opt[min] caracteres");
return false;
}
if (strlen($this->$f) > $opt['max']) {
if (isset($opt['too_long']))
Flash::error($opt['too_long']);
else
Flash::error("Error: El campo $field debe tener como máximo $opt[max] caracteres");
return false;
}
}
}
}
/**
* Validacion validates_inclusion
*
*/
foreach($this->_validates['inclusion_in'] as $f => $opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
if (!in_array($this->$f, $opt['list'])) {
if (isset($opt['message'])) {
Flash::error($opt['message']);
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("$field debe tener un valor entre (" . join(",", $opt['list']) . ")");
}
return false;
}
}
}
/**
* Validacion validates_exclusion
*
*/
foreach($this->_validates['exclusion_of'] as $f => $opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
if (in_array($this->$f, $opt['list'])) {
if (isset($opt['message'])) {
Flash::error($opt['message']);
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("$field no debe tener un valor entre (" . join(",", $opt['list']) . ")");
}
return false;
}
}
}
/**
* Validacion validates_numericality
*
*/
foreach($this->_validates['numericality_of'] as $f => $opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
if (!is_numeric($this->$f)) {
if (isset($opt['message'])) {
Flash::error($opt['message']);
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("$field debe tener un valor numérico");
}
return false;
}
}
}
/**
* Validacion validates_format
*
*/
foreach($this->_validates['format_of'] as $f => $opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
if (!filter_var($this->$f, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>$opt['pattern'])))) {
if (isset($opt['message'])) {
Flash::error($opt['message']);
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("Formato erroneo para $field");
}
return false;
}
}
}
/**
* Validacion validates_date
*
*/
foreach($this->_validates['date_in'] as $f => $opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
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])$/")))) {
if (isset($opt['message'])) {
Flash::error($opt['message']);
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("Formato de fecha erroneo para $field");
}
return false;
}
}
}
/**
* Validacion validates_email
*
*/
foreach($this->_validates['email_in'] as $f=>$opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
if (!filter_var($this->$f, FILTER_VALIDATE_EMAIL)) {
if (isset($opt['message'])) {
Flash::error($opt['message']);
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("Formato de e-mail erroneo en el campo $field");
}
return false;
}
}
}
/**
* Validacion validates_uniqueness
*
*/
foreach($this->_validates['uniqueness_of'] as $f => $opt) {
if (isset($this->$f) && !is_null($this->$f) && $this->$f != '') {
$result = $this->db->fetch_one("SELECT COUNT(*) FROM $table WHERE $f = {$this->db->add_quotes($this->$f)}");
if ($result[0]) {
if (isset($opt['message'])) {
Flash::error($opt['message']);
} else {
$field = isset($opt['field']) ? $opt['field'] : $f;
Flash::error("El valor '{$this->$f}' ya existe para el campo $field");
}
return false;
}
}
}
#Run Validation Callbacks After
if(!$ex){
if (method_exists($this, "after_validation_on_create")) {
if ($this->after_validation_on_create() == 'cancel') {
return false;
}
} else {
if (isset($this->after_validation_on_create)) {
$method = $this->after_validation_on_create;
if ($this->$method() == 'cancel') {
return false;
}
}
}
}
if($ex){
if (method_exists($this, "after_validation_on_update")) {
if ($this->after_validation_on_update() == 'cancel') {
return false;
}
} else {
if (isset($this->after_validation_on_update)) {
$method = $this->after_validation_on_update;
if ($this->$method() == 'cancel') return false;
}
}
}
if (method_exists($this, 'after_validation')) {
if ($this->after_validation() == 'cancel') {
return false;
}
} else {
if (isset($this->after_validation)) {
$method = $this->after_validation;
if ($this->$method() == 'cancel') {
return false;
}
}
}
# Run Before Callbacks
if (method_exists($this, "before_save")) {
if ($this->before_save() == 'cancel') {
return false;
}
} else {
if (isset($this->before_save)) {
$method = $this->before_save;
if ($this->$method() == 'cancel') {
return false;
}
}
}
if($ex){
if (method_exists($this, "before_update")) {
if ($this->before_update() == 'cancel') {
return false;
}
} else {
if (isset($this->before_update)) {
$method = $this->before_update;
if ($this->$method() == 'cancel') {
return false;
}
}
}
}
if(!$ex){
if (method_exists($this, "before_create")) {
if ($this->before_create() == 'cancel') {
return false;
}
} else {
if (isset($this->before_create)) {
$method = $this->before_create;
if ($this->$method() == 'cancel') {
return false;
}
}
}
}
$environment = Config::read('databases');
$config = $environment[$this->get_database()];
if ($ex) {
$fields = array();
$values = array();
foreach($this->non_primary as $np) {
$np = ActiveRecord::sql_item_sanizite($np);
if (in_array($np, $this->_in)) {
if ($config['type'] == 'oracle') {
$this->$np = date("Y-m-d");
} else {
$this->$np = date("Y-m-d G:i:s");
}
}
if (isset($this->$np)) {
$fields[] = $np;
if (is_null($this->$np) || $this->$np == '') {
$values[] = "NULL";
} elseif (substr($this->$np, 0, 1) == "%") {
$values[] = str_replace("%", "", $this->$np);
} else {
/**
* Se debe especificar el formato de fecha en Oracle
*/
if ($this->_data_type[$np] == 'date' && $config['type'] == 'oracle') {
$values[] = "TO_DATE(" . $this->db->add_quotes($this->$np) . ", 'YYYY-MM-DD')";
} else {
$values[] = $this->db->add_quotes($this->$np);
}
}
}
}
$val = $this->db->update($table, $fields, $values, $this->_where_pk);
} else {
$fields = array();
$values = array();
foreach($this->fields as $field) {
if ($field != 'id' && !$this->id) {
if (in_array($field, $this->_at)) {
if ($config['type'] == 'oracle') {
$this->$field = date("Y-m-d");
} else {
$this->$field = date("Y-m-d G:i:s");
}
}
if (in_array($field, $this->_in)) {
unset($this->$field);
}
$use_default = in_array($field, $this->_with_default) && isset($this->$field) && (is_null($this->$field) || $this->$field == '');
if($this->_data_type[$field] == 'datetime' && $config['type'] == 'mysql'){
$this->$field = date("Y-m-d G:i:s",strtotime($this->$field));
}
if (isset($this->$field) && !$use_default) {
$fields[] = ActiveRecord::sql_sanizite($field);
if (substr($this->$field, 0, 1) == "%") {
$values[] = str_replace("%", "", $this->$field);
} else {
if ($this->is_a_numeric_type($field) || $this->$field == null) {
$values[] = addslashes($this->$field !== '' && $this->$field !== null ? $this->$field : "NULL");
} else {
if ($this->_data_type[$field] == 'date' && $config['type'] == 'oracle') {
/**
* Se debe especificar el formato de fecha en Oracle
*/
$values[] = "TO_DATE(" . $this->db->add_quotes($this->$field) . ", 'YYYY-MM-DD')";
} else {
if (!is_null($this->$field) && $this->$field != '') {
$values[] = $this->db->add_quotes($this->$field);
} else {
$values[] = "NULL";
}
}
}
}
}
} else {
/**
* Campos autonumericos en Oracle deben utilizar una sequencia auxiliar
*/
if ($config['type'] == 'oracle') {
if (!$this->id) {
$fields[] = "id";
$values[] = $this->source . "_id_seq.NEXTVAL";
}
}
if ($config['type'] == 'informix') {
if (!$this->id) {
$fields[] = "id";
$values[] = 0;
}
}
}
}
$val = $this->db->insert($table, $values, $fields);
}
if (!isset($config['pdo']) && $config['type'] == 'oracle') {
$this->commit();
}
if (!$ex) {
//$this->db->logger = true;
$m = $this->db->last_insert_id($table, $this->primary_key[0]);
$this->find_first($m);
}
if ($val) {
if($ex){
if (method_exists($this, "after_update")) {
if ($this->after_update() == 'cancel') {
return false;
}
} else {
if (isset($this->after_update)) {
$method = $this->after_update;
if ($this->$method() == 'cancel') {
return false;
}
}
}
}
if(!$ex){
if (method_exists($this, "after_create")) {
if ($this->after_create() == 'cancel') {
return false;
}
} else {
if (isset($this->after_create)) {
$method = $this->after_create;
if ($this->$method() == 'cancel') {
return false;
}
}
}
}
if (method_exists($this, "after_save")) {
if ($this->after_save() == 'cancel') {
return false;
}
} else {
if (isset($this->after_save)) {
$method = $this->after_save;
if ($this->$method() == 'cancel') {
return false;
}
}
}
return $val;
} else {
return false;
}
}
/**
* Find All data in the Relational Table
*
* @param string $field
* @param string $value
* @return ActiveRecod Cursor
*/
function find_all_by($field, $value)
{
ActiveRecord::sql_item_sanizite($field);
return $this->find("conditions: $field = {$this->db->add_quotes($value) }");
}
/**
* Updates Data in the Relational Table
*
* @param mixed $values
* @return boolean sucess
*/
function update()
{
if (func_num_args() > 0) {
$params = Util::getParams(func_get_args());
$values = (isset($params[0]) && is_array($params[0])) ? $params[0] : $params;
foreach($this->fields as $field) {
if (isset($values[$field])) {
$this->$field = $values[$field];
}
}
}
if ($this->exists()) {
if (method_exists($this, 'before_change')) {
$obj = clone $this;
if($this->before_change($obj->find($this->id)) == 'cancel'){
return false;
}
unset($obj);
}
if($this->save()){
if (method_exists($this, 'after_change')) {
if ($this->after_change($this) == 'cancel') {
return false;
}
}
return true;
}
} else {
Flash::error('No se puede actualizar porque el registro no existe');
return false;
}
}
/**
* Deletes data from Relational Map Table
*
* @param mixed $what
*/
public function delete($what = '')
{
if (func_num_args() > 1) {
$what = Util::getParams(func_get_args());
}
if ($this->schema) {
$table = $this->schema . "." . $this->source;
} else {
$table = $this->source;
}
$conditions = "";
if (is_array($what)) {
if ($what["conditions"]) {
$conditions = $what["conditions"];
}
} else {
if (is_numeric($what)) {
ActiveRecord::sql_sanizite($this->primary_key[0]);
$conditions = "{$this->primary_key[0]} = '$what'";
} else {
if ($what) {
$conditions = $what;
} else {
ActiveRecord::sql_sanizite($this->primary_key[0]);
$conditions = "{$this->primary_key[0]} = '{$this->{$this->primary_key[0]}}'";
}
}
}
if (method_exists($this, "before_delete")) {
if ($this->id) {
$this->find($this->id);
}
if ($this->before_delete() == 'cancel') {
return false;
}
} else {
if (isset($this->before_delete)) {
if ($this->id) {
$this->find($this->id);
}
$method = $this->before_delete;
if ($this->$method() == 'cancel') {
return false;
}
}
}
$val = $this->db->delete($table, $conditions);
if ($val) {
if (method_exists($this, "after_delete")) {
if ($this->after_delete() == 'cancel') {
return false;
}
} else {
if (isset($this->after_delete)) {
$method = $this->after_delete;
if ($this->$method() == 'cancel') {
return false;
}
}
}
}
return $val;
}
/**
* Actualiza todos los atributos de la entidad
* $Clientes->update_all("estado='A', fecha='2005-02-02'", "id>100");
* $Clientes->update_all("estado='A', fecha='2005-02-02'", "id>100", "limit: 10");
*
* @param string $values
*/
public function update_all($values) {
$params = array();
if ($this->schema) {
$table = $this->schema . "." . $this->source;
} else {
$table = $this->source;
}
if (func_num_args() > 1) {
$params = Util::getParams(func_get_args());
}
if (!isset($params['conditions']) || !$params['conditions']) {
if (isset($params[1])) {
$params['conditions'] = $params[1];
} else {
$params['conditions'] = "";
}
}
if ($params['conditions']) {
$params['conditions'] = " WHERE " . $params['conditions'];
}
$sql = "UPDATE $table SET $values {$params['conditions']}";
$limit_args = array($sql);
if (isset($params['limit'])) {
array_push($limit_args, "limit: $params[limit]");
}
if (isset($params['offset'])) {
array_push($limit_args, "offset: $params[offset]");
}
if (count($limit_args) > 1) {
$sql = call_user_func_array(array($this, 'limit'), $limit_args);
}
$environment = Config::read('databases');
$config = $environment[$this->get_database()];
if (!isset($config->pdo) || !$config->pdo) {
if ($config['type'] == "informix") {
$this->db->set_return_rows(false);
}
}
return $this->db->query($sql);
}
/**
* Delete All data from Relational Map Table
*
* @param string $conditions
* @return boolean
*/
public function delete_all($conditions = '') {
$limit = "";
if ($this->schema) {
$table = $this->schema . "." . $this->source;
} else {
$table = $this->source;
}
if (func_num_args() > 1) {
$params = Util::getParams(func_get_args());
$limit_args = array($select);
if (isset($params['limit'])) {
array_push($limit_args, "limit: $params[limit]");
}
if (isset($params['offset'])) {
array_push($limit_args, "offset: $params[offset]");
}
if (count($limit_args) > 1) {
$select = call_user_func_array(array($this, 'limit'), $limit_args);
}
}
return $this->db->delete($table, $conditions);
}
/**
* *********************************************************************************
* Metodos de Debug
* *********************************************************************************
*/
/**
* Imprime una version humana de los valores de los campos
* del modelo en una sola linea
*
*/
public function inspect() {
$inspect = array();
foreach($this->fields as $field) {
if (!is_array($field)) {
$inspect[] = "$field: {$this->$field}";
}
}
return join(", ", $inspect);
}
/**
* *********************************************************************************
* Metodos de Validacion
* *********************************************************************************
*/
/**
* Valida que el campo no sea nulo
*
* @param string $field campo a validar
* @param array $params parametros adicionales
*
* message: mensaje a mostrar
* field: nombre de campo a mostrar en el mensaje
*/
protected function validates_presence_of($field, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['presence_of'][$field] = $params;
}
/**
* Valida el tamañoo de ciertos campos antes de insertar
* o actualizar
*
* @params string $field campo a validar
* @param int $max valor maximo
* @param int $min valor minimo
* @param array $params parametros adicionales
*
* too_short: mensaje a mostrar cuando se muy corto
* too_long: mensaje a mostrar cuando sea muy largo
* field: nombre de campo a mostrar en el mensaje
*/
protected function validates_length_of($field, $max, $min=0, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['length_of'][$field] = $params;
$this->_validates['length_of'][$field]['min'] = $min;
$this->_validates['length_of'][$field]['max'] = $max;
}
/**
* Valida que el campo se encuentre entre los valores de una lista
* antes de insertar o actualizar
*
* @param string $field campo a validar
* @param array $list
*
* message: mensaje a mostrar
* field: nombre del campo a mostrar en el mensaje
*/
protected function validates_inclusion_in($field, $list, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['inclusion_in'][$field] = $params;
$this->_validates['inclusion_in'][$field]['list'] = $list;
}
/**
* Valida que el campo no se encuentre entre los valores de una lista
* antes de insertar o actualizar
*
* @param string $field campo a validar
* @param array $list
*
* message: mensaje a mostrar
* field: nombre del campo a mostrar en el mensaje
*/
protected function validates_exclusion_of($field, $list, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['exclusion_of'][$field] = $params;
$this->_validates['exclusion_of'][$field]['list'] = $list;
}
/**
* Valida que el campo tenga determinado formato segun una expresion regular
* antes de insertar o actualizar
*
* @param string $field campo a validar
* @param string $pattern expresion regular para preg_match
*
* message: mensaje a mostrar
* field: nombre del campo a mostrar en el mensaje
*/
protected function validates_format_of($field, $pattern, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['format_of'][$field] = $params;
$this->_validates['format_of'][$field]['pattern'] = $pattern;
}
/**
* Valida que ciertos atributos tengan un valor numerico
* antes de insertar o actualizar
*
* @param string $field campo a validar
*
* message: mensaje a mostrar
* field: nombre del campo a mostrar en el mensaje
*/
protected function validates_numericality_of($field, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['numericality_of'][$field] = $params;
}
/**
* Valida que ciertos atributos tengan un formato de e-mail correcto
* antes de insertar o actualizar
*
* @param string $field campo a validar
*
* message: mensaje a mostrar
* field: nombre del campo a mostrar en el mensaje
*/
protected function validates_email_in($field, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['email_in'][$field] = $params;
}
/**
* Valida que ciertos atributos tengan un valor unico antes
* de insertar o actualizar
*
* @param string $field campo a validar
*
* message: mensaje a mostrar
* field: nombre del campo a mostrar en el mensaje
*/
protected function validates_uniqueness_of($field, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['uniqueness_of'][$field] = $params;
}
/**
* Valida que ciertos atributos tengan un formato de fecha acorde al indicado en
* config/config.ini antes de insertar o actualizar
*
* @param string $field campo a validar
*
* message: mensaje a mostrar
* field: nombre del campo a mostrar en el mensaje
*/
protected function validates_date_in($field, $params=array())
{
if (is_string($params))
$params = Util::getParams(func_get_args());
$this->_validates['date_in'][$field] = $params;
}
/**
* Verifica si un campo es de tipo de dato numerico o no
*
* @param string $field
* @return boolean
*/
public function is_a_numeric_type($field)
{
if (strpos(" " . $this->_data_type[$field], "int") || strpos(" " . $this->_data_type[$field], "decimal") || strpos(" " . $this->_data_type[$field], "number")) {
return true;
} else {
return false;
}
}
/**
* Obtiene los datos de los metadatos generados por Primera vez en la Sesión
*
* @param string $table
* @return array
*/
static function get_meta_data($table)
{
if (isset(self::$models[$table])) {
return self::$models[$table];
} elseif(PRODUCTION && ($metadata = Cache::get($table, 'kumbia.models'))) {
self::$models[$table] = unserialize($metadata);
return $metadata;
}
return array();
}
/**
* Crea un registro de meta datos para la tabla especificada
*
* @param string $table
* @param array $meta_data
*/
static function set_meta_data($table, $meta_data)
{
if(PRODUCTION) {
Cache::save(serialize($meta_data), Config::get('config.application.metadata_lifetime'), $table, 'kumbia.models');
}
self::$models[$table] = $meta_data;
return true;
}
/*******************************************************************************************
* Metodos para generacion de relaciones
*******************************************************************************************/
/**
* Crea una relacion 1-1 entre dos modelos
*
* @param string $relation
*
* model : nombre del modelo al que se refiere
* fk : campo por el cual se relaciona (llave foranea)
*/
protected function has_one($relation)
{
$params = Util::getParams(func_get_args());
for ($i = 0;isset($params[$i]);$i++) {
$relation = Util::uncamelize($params[$i]);
if (!array_key_exists($relation, $this->_has_one)) {
$this->_has_one[$relation] = new stdClass();
$this->_has_one[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
$this->_has_one[$relation]->fk = isset($params['fk']) ? $params['fk'] : Util::uncamelize(get_class($this)) . '_id';
}
}
}
/**
* Crea una relacion 1-1 inversa entre dos modelos
*
* @param string $relation
*
* model : nombre del modelo al que se refiere
* fk : campo por el cual se relaciona (llave foranea)
*/
protected function belongs_to($relation)
{
$params = Util::getParams(func_get_args());
for ($i = 0;isset($params[$i]);$i++) {
$relation = Util::uncamelize($params[$i]);
if (!array_key_exists($relation, $this->_belongs_to)) {
$this->_belongs_to[$relation] = new stdClass();
$this->_belongs_to[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
$this->_belongs_to[$relation]->fk = isset($params['fk']) ? $params['fk'] : "{$relation}_id";
}
}
}
/**
* Crea una relacion 1-n entre dos modelos
*
* @param string $relation
*
* model : nombre del modelo al que se refiere
* fk : campo por el cual se relaciona (llave foranea)
*/
protected function has_many($relation)
{
$params = Util::getParams(func_get_args());
for ($i = 0;isset($params[$i]);$i++) {
$relation = Util::uncamelize($params[$i]);
if (!array_key_exists($relation, $this->_has_many)) {
$this->_has_many[$relation] = new stdClass();
$this->_has_many[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
$this->_has_many[$relation]->fk = isset($params['fk']) ? $params['fk'] : Util::uncamelize(get_class($this)) . '_id';
}
}
}
/**
* Crea una relacion n-n o 1-n inversa entre dos modelos
*
* @param string $relation
*
* model : nombre del modelo al que se refiere
* fk : campo por el cual se relaciona (llave foranea)
* key: campo llave que identifica al propio modelo
* through : atrav�s de que tabla
*/
protected function has_and_belongs_to_many($relation)
{
$params = Util::getParams(func_get_args());
for ($i = 0;isset($params[$i]);$i++) {
$relation = Util::uncamelize($params[$i]);
if (!array_key_exists($relation, $this->_has_and_belongs_to_many)) {
$this->_has_and_belongs_to_many[$relation] = new stdClass();
$this->_has_and_belongs_to_many[$relation]->model = isset($params['model']) ? $params['model'] : $relation;
$this->_has_and_belongs_to_many[$relation]->fk = isset($params['fk']) ? $params['fk'] : "{$relation}_id";
$this->_has_and_belongs_to_many[$relation]->key = isset($params['key']) ? $params['key'] : Util::uncamelize(get_class($this)) . '_id';
if (isset($params['through'])) {
$this->_has_and_belongs_to_many[$relation]->through = $params['through'];
}
}
}
}
/**
* Herencia Simple
*/
/**
* Especifica que la clase es padre de otra
*
* @param string $parent
*/
public function parent_of($parent)
{
$parents = func_get_args();
foreach($parents as $parent) {
if (!in_array($parent, $this->parent_of)) {
$this->parent_of[] = $parent;
}
}
}
/**
* Elimina caracteres que podrian ayudar a ejecutar
* un ataque de Inyeccion SQL
*
* @param string $sql_item
*/
public static function sql_item_sanizite($sql_item)
{
$sql_item = trim($sql_item);
if ($sql_item !== '' && $sql_item !== null) {
$sql_item = ereg_replace("[ ]+", "", $sql_item);
if (!ereg("^[a-zA-Z0-9_\.]+$", $sql_item)) {
throw new ActiveRecordException("Se esta tratando de ejecutar una operacion maliciosa!");
}
}
return $sql_item;
}
/**
* Elimina caracteres que podrian ayudar a ejecutar
* un ataque de Inyeccion SQL
*
* @param string $sql_item
*/
public static function sql_sanizite($sql_item)
{
$sql_item = trim($sql_item);
if ($sql_item !== '' && $sql_item !== null) {
$sql_item = ereg_replace("[ ]+", "", $sql_item);
if (!ereg("^[a-zA-Z_0-9\,\(\)\.\*]+$", $sql_item)) {
throw new ActiveRecordException("Se esta tratando de ejecutar una operacion maliciosa!");
}
}
return $sql_item;
}
/**
* Al sobreescribir este metodo se puede controlar las excepciones de un modelo
*
* @param unknown_type $e
*/
protected function exceptions($e)
{
throw $e;
}
/**
* Implementacion de __toString Standard
*
*/
public function __toString()
{
return "<" . get_class() . " Object>";
}
/**
* Paginador para el modelo
*
* conditions: condiciones para paginacion
* page: numero de pagina a mostrar (por defecto la pagina 1)
* per_page: cantidad de elementos por pagina (por defecto 10 items por pagina)
*
* @return un objeto Page identico al que se regresa con el util paginate
*
*/
public function paginate()
{
$args = func_get_args();
array_unshift($args, $this->source);
if(!class_exists('Paginator')){
require CORE_PATH . 'libs/db/behaviors/paginate.php';
}
return call_user_func_array(array('Paginator' , 'paginate'), $args);
}
/**
* Paginador para el modelo atraves de consulta sql
*
* @param string $sql consulta sql
*
* page: numero de pagina a mostrar (por defecto la pagina 1)
* per_page: cantidad de elementos por pagina (por defecto 10 items por pagina)
*
* @return un objeto Page identico al que se regresa con el util paginate_by_sql
*
*/
public function paginate_by_sql($sql)
{
$args = func_get_args();
array_unshift($args, $this->source);
if(!class_exists('Paginator')){
require CORE_PATH . 'libs/db/behaviors/paginate.php';
}
return call_user_func_array(array('Paginator' , 'paginate_by_sql'), $args);
}
/**
* Operaciones al serializar
*
**/
public function __sleep()
{
/**
* Anulando conexion a bd en el modelo
**/
$this->db = null;
return array_keys(get_object_vars($this));
}
/**
* Operaciones al deserializar
*
**/
public function __wakeup()
{
/**
* Restableciendo conexion a la bd
**/
$this->_connect();
}
/**
* Obtiene la instacia de un modelo
*
* @param string $model
* @return ActiveRecord
* @throw KumbiaException
**/
public static function get($model)
{
if(isset(self::$_models[$model])) {
return self::$_models[$model];
}
/**
* Nombre de la clase
**/
$Model = Util::camelcase(basename($model));
/**
* Verifico si esta cargada la clase
**/
if(!class_exists($Model, false)) {
/**
* Carga la clase
**/
$file = APP_PATH . "models/$model.php";
if(is_file($file)) {
include $file;
} else {
throw new KumbiaException("No existe el modelo ActiveRecord $model");
}
}
self::$_models[$model] = $obj = new $Model();
return $obj;
}
}