Páginas

miércoles, 15 de diciembre de 2010

clase para conexion utilizando PDO, el patron factory, confireader y registry

buenas para este segundo post ahora si trabajaremos con PHP, utilizaremos el patrón de diseño factory y registry para realizar una conexión a base de datos.

Para realizar la conexión trabajaremos con PHP Data Objects (PDO), lo que nos dará una abstracción de base de datos permitiendo que nuestro script pueda conectar con diferentes manejadores, en nuestro caso usaremos MySQL, bueno ahora si manos a la obra:

Lo primero que creamos es  el archivo con la configuración:

config.ini

[MySql]
host     = 'localhost'
dbname   = 'db'
username = 'root'
password = ''

acá vamos a indicar los parámetros para instanciar el dns de PDO en este caso con MySQL
[CITA]
$db = new PDO ( 'mysql:host=localhost;dbname=<SOMEDB>' , '<USERNAME>' , '<PASSWORD>' );
[/CITA]
esta pequeña cita es del manual donde nos indica que dns para instanciar PDO, como vemos los todos los parámetros los tenemos dentro de nuestro archivo config.ini.

ahora hacemos uso de la clase configReader para leer el archivo config.ini y así obtener los parámetros que necesitamos para el dns de nuestra clase

configReader.php

<?php
class ConfigReader
{
    private $_config;
    public function __construct($archivo)
    {                  
     if (!file_exists($archivo)) {
            throw new Exception('No se encontro el archivo: '.$archivo);
        }   
        $this->_config = parse_ini_file($archivo, true);
    }
 
    public function getConfig()
    {
        return $this->_config;
    }
}
?>

ahora vamos a crear la clase que nos permitirá conectar con MySQL

mysql.php

<?php
final class MySQL extends PDO
{
    private $_username;
    private $_password;
    private $_host;
    private $_db;
 
    public function __construct(ConfigReader $config)
    {
        $config_data = $config->getConfig();
        $this->_username = $config_data['MySql']['username'];
        $this->_password = $config_data['MySql']['password'];
        $this->_host = $config_data['MySql']['host'];
        $this->_db = $config_data['MySql']['dbname'];
        $this->_dsn = 'mysql:host='.$this->_host.';dbname='.$this->_db;
        parent::__construct($this->_dsn, $this->_username, $this->_password);     
    }
}
?>

si nos damos cuenta esta clase no es extendible ya que tiene la palabra final, ademas exiende directamente de PDO, lo que esta clase hace es la instancia para trabajar con MySQL en PDO, vemos el DNS que colocabamos al principio, los parametros los extraemos de la isntancia de la clase confiReader que pedimos como parametro en el constructor de nuestra clase MySQL.

Ahora vamos a trabajar el patron factory que nos permite instanciar objetos de un subtipo en este caso el subtipo sera MySQL

primero creamos la interface

DbFactory_Interface.php

<?php
interface DbFactory_Interface
{
    public static function create($sIniFile);
}
?>

ahora la clase dbfactory que implementa la interface creada anteriormente

dbfactory.php
<?php
error_reporting ( E_ALL );
ini_set ( "display_errors" , 1 ); 
include("DbFactory_Interface.php");
include("registry.php");
include("ConfiReader.php");
include("db.php");
class DatabaseFactory implements DbFactory_Interface
{   
    public static function create($sIniFile)
    {        
        $config = new ConfigReader($sIniFile);        
        $config_data = $config->getConfig();
        $database_class = key($config_data);
        include($database_class.'.php');
        $db = new $database_class($config);
        Registry::add($sIniFile, $db);       
        return $db;
    }
}
?>
en este archivo incluimos todas nuestras clases que vamos a utilizar para que nuestra clase de conexion haga  el trabajo. Si se fijan dentro de esta clase es utiliza el patron registry para poder realizar diferentes instancias de la clase, ya que la clase si necesitamos conectar con varios manejadores de base de datos podemos hacerlo solo creando el archivo .ini dandole los parametros del DNS de PDO para el manejador con el que deseemos conectar y el archivo con la clase que extiende de PDO donde indicamos con que manejador conectar en nuestro caso MySQL.php, aca le dejo el patron registry

<?php
class registry
{
     static private $registry = array();     
     public function add($name, &$item)
     {
         if (!self::exists($name)) {
             self::$registry[$name] = $item;
             return true;
         } else {
             return false;
         }
     }      
      public function exists($name)
     {
         if (is_string($name)) {
             return array_key_exists($name, self::$registry);
         } else {
             throw new Exception('Registry item\'s name must be a string');
         }
     }
     public function &get($name)
     {
         if (self::exists($name)) {
             $return = self::$registry[$name];
         } else {
             $return = NULL;
         }
         return $return;
     }    
 }
 ?>
 pues ahora solo nos falta crear la clase que se va a encargar de ejecutar las sentencias en este caso yo realize una clase para la ejecucion de consultas preparadas de manera que se evite la inyeccion sql ya que es importante el tema de la seguridad.


<?php 
   #######################################################
   #          Clace para conexion con db                 #
   #                                                     #
   #   Creado por Carlos  Belisario                 #
   #                                                     #
   #                                                     #
   #   Fecha: 20/11/2010                                 #
   #                                                     #
   #######################################################
 class db
{
    /*establese la conexion*/
    protected $_conect;
    /*trabaja los query*/
    protected $_query;
    /*resultados de las consultas*/
    protected $_row;
    protected $_result;
    public function __construct()
    {
        $site_path = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR.'config.ini';
        $this->_conect=DatabaseFactory::create($site_path);
    }
    /*trae todos los datos de las tablas indicadas en el array tabla*/
    public function selectAll($table = array(),$condicion = array(),$relacion = array()){
        $result = array();
        try{           
            if(!array($table)){
                die("Las Tablas deben de estar en formato arreglo");
            }
            if(count($table)>1){               
                foreach($table as $id=>$valor){                   
                    if($id==0){
                        $tablas = $valor." INNER JOIN ".next($table)." ON(".$relacion[$id].")";                       
                    }
                    else{
                        if($id!=1){                       
                            $tablas.= " INNER JOIN ".$valor." ON(".$relacion[$id-1].")";
                        }
                    }
                }                           
            }           
            else{
                $tablas = $table[0];
            }
            if(empty($condicion))
            {
                $sql = "SELECT * FROM $tablas";               
                $this->_query = $this->_conect->prepare($sql);
                $this->_query->execute();
            }
            else{               
                foreach($condicion as $key=>$value){
                    $parametros[] = "$key=?";
                    $condic[] = $value;
                }           
                $condiciones = implode(" AND ",$parametros);
                $sql = "SELECT * FROM $tablas WHERE $condiciones";               
               $this->_query = $this->_conect->prepare($sql);               
                $this->_query->execute($condic);
            }   
            while($this->_row = $this->_query->fetch()){   
                $result[] = $this->_row;           
            }           
            return $result;
        }
        catch(PDOExeption $e){
            echo $e->getMessaage();
        }
    }   
    /*ejecuta una sentencia de MySQL Preparada usando el formato de PDO*/
    public function ejecutarSentencia($query,$parametro = NULL,$return = false)
    {
        $result=array();
        try{                   
            $this->_query = $this->_conect->prepare($query);
            $this->_query->execute($parametro);   
            if($return==true){                                   
                while($this->_row = $this->_query->fetch()){   
                    $result[] = $this->_row;
                }               
                return $result;
            }           
        }
        catch(PDOExeption $e){
            echo $e->getMessaage();
        }
    }       
    /*inserta registros en la base de datos*/     
    public function insert($table,$valores)
    {
        if(!is_array($valores)){
            echo "Los datos deben de estar en formato de arreglo";
        }
        try{               
            foreach($valores as $id=>$valor){                               
                $parametros[] = '?';                               
                $campos[] = $id;   
                $value[] = $valor;
            }
            $val = implode(",",$parametros);
            if(!empty($campos)){
                $fields = implode(",",$campos);
                $sql = "INSERT INTO $table ($fields) VALUES ($val)";           
            }               
            $insert=$this->_conect->prepare($sql);           
            $insert->execute($value);
        }
        catch(PDOExeption $e){
            echo $e->getMessaage();
        }   
    }   
    /*Actualiza registros de la base de datos*/
    public function update($table,$valores,$condicion)
    {
        if(!is_array($valores)){
            echo "Los datos deben de estar en formato de arreglo";
        }
        try{           
            foreach($valores as $id=>$valor){
                $parametro[]="$id=?";
                $values[]=$valor;
            }
            foreach($condicion as $key=>$value){
                $de=explode(".",$value);
                if(count($de)>1){
                    $parametro_condicion[]="$key=$value";                   
                }
                else{
                    $parametro_condicion[]="$key=?";
                    $values[]=$value;                   
                }
            }               
            $parm=implode(",",$parametro);           
            if(count($condiciones)>0){
                $condiciones=implode(" AND ",$parametro_condicion);
                $sql="UPDATE $table SET $parm WHERE $condiciones"
            }       
            else{
                $sql="UPDATE $table SET $parm"
            }                                                   
            $update=$this->_conect->prepare($sql);           
            $update->execute($values);
        }
        catch(PDOExeption $e){
            echo $e->getMessaage();
        }   
    }
    /*borra registros de la base de datos*/
    public function deleteAll($table,$condicion = NULL,$return = false)
    {
        try{   
            foreach($condicion as $key=>$value){
                $de=explode(".",$value);
                if(count($de)>1){
                    $valorCondicion[] = "$key=".$value;
                }
                else{
                    $valorCondicion[] = "$key='".$value."'";
                }
            }               
            $condiciones = implode(" AND ",$valorCondicion);               
           $this->_result = $this->_conect->exec("DELETE FROM $table WHERE $condiciones");           
            if($return){
                return $this->_result;
            }               
        }
        catch(PDOExeption $e){
            echo $e->getMessaage();
        }
    }
    #reinicia la base de datos 
    public function reiniciarTabla($table){
        try{           
            $this->_result = $this->_conect->exec("TRUNCATE TABLE $table");               
        }
        catch(PDOExeption $e){
            echo $e->getMessaage();
        }
    }
}

si se fijan en el constructor de nuestra esta clase es donde comienza la magia (:-) e instanciamos la clase dbfactory que es la que se va a encargar de que se llamen a las clases que necesitamos, luego tenemos una serie de metodos para la ejecucion de consultas sql como usar:


<?php
#incluimos el archivo donde estan todas las clases
include("dbfactory.php");
#instanciamos la clase db() que es la que se encarga de trabajar el estandar e instanciar la clase dbfactory
$db = new db();
$rows = $db->selectAll("tabla",array('campo'=>'condicion'));
?>

 si se fijan utilice el metodo select all  si hicieramos un print_r($rows) si la consulta trajo resultados se mostrara

Array ( [0] => Array ( [correlativo] => SAL-0 [0] => SAL-0) [1] => Array ( [correlativo] => SAL-1 [0] => SAL-1)) 

como se puede notar todas las consultas son  consultas preparadas, menos las de borrar y reiniciar la tabla, estan bastante facil de entender su funcionamiento y estan comentadas espero que este articulo le sirva, saludos

martes, 14 de diciembre de 2010

Usos de la funcion DATE_FORMAT de MySQL

   Bueno como primera entrada de este Blog que fue creado para el aprendizade del Desarrollo Web, quiero comenzar con algo sencillo pero que ayuda bastante.

   Muchas veces al momento de mostrar fechas traidas de una consulta de base de datos nos encontramos con el formato americano (un probelma para algunos, ya que muchos deseamos que nos aparezca en formato de dia mes y año), cuando comence a trabajar con PHP sencillamente usaba la funcion explode separaba la fecha y la colocaba en el formato que deseaba (dd-mm-YYYY), una buena solución pero no la mas optima ya que MySQL nos permite traer las fechas en el formato que deseamos mediante su funcion DATE_FORMAT, con la que nos ahorramos todo el trabajo de separar y luego concatenar algo que acabamos de separar ( un poco enrredado no creen).

Para evitarnos eso utilizamos esta funcion, que solo nos pide dos parametros, el primero es la fecha en formato MySQL date/time (bien sea un campo o una cadena indicada en la consulta), el segundo es el formato en que se desea obtener la fecha de la consulta, dentro del formato que deseamos optener en el  manual nos indican cuales son los posibles formatos., son muy parecidos a los que se utiliza cuando trabajamos la funcion Date de php, todos antecedidos por el comodin de MySQL "%" bueno vamos a ver un pequeño ejemplo:

SELECT DATE_FORMAT(campo_fe,'%d/%m%Y') as "fecha formateada" FROM tabla;
el resultado seria:

--------------------------------------
|       fecha formateada            |
--------------------------------------
|         14/12/2010                   |
--------------------------------------

ahora bien, aveces algunos tenemos calendarios para selecionar fechas de un formulario, por ejemplo tenemos una pagina para busqueda en rango de fecha pero el formato que devuelve el calendario es mes/dia/año y no conocemos como configurar el calendario para obtener la fecha en el formato deseado (pasa mucho), que hacemos el explode y lo convertimos a fecha  en formato MySQL?? pues la funcion date_format tambien se puede utilizar en el condicional de la consulta por ejemplo
SELECT * FROM auditoria WHERE DATE_FORMAT(fecha,'%m/%d/%Y') BETWEEN '12/01/2010' AND '12/14/2010';
de esta manera tendriamos una auditoria entre ese rango de fechas.

igual si se desea buscar por ejemplo todos los  14 de Diciembre, sencillamente con indicarle al parametro de la funcion que busque solo ese dia y ese mes tendriamos nuestro resultado fijense:
SELECT * FROM tabla WHERE date_format(fecha,'%d-%m')='14-12';
tambien se puede al igual que con la funcion DAY(), MONTH() y YEAR() hacer una consulta diciendo solamente el dia,mes o año de la fecha que se desea buscar ejemplo:
SELECT * FROM tabla WHERE date_format(fecha, '%d')='14';
SELECT * FROM tabla WHERE date_format(fecha,'%m')='12';
SELECT * FROM tabla WHERE date_format(fecha,'%Y')='2010';
y que con las horas?? pues date format tambien te permite establecer el formato de horas en que deseas que se traiga tu consulta un ejemplo:
suponiendo que tenemos en un campo hora las 14:30:00 y deseamos que se muestre la hora con formato AM/PM sencillamente lo que debemos hacer es utilizar nuestra funcion
SELECT date_format(hora,'%h:%i:%s %p') FROM table;
el resultado seria

--------------------------------------
|       hora formateada            |
--------------------------------------
|         02:30:00 PM              |
--------------------------------------
bueno aca indique los usos que se le puede dar a esta funcion, que puede que paresca sencilla pero pero muy util al momento de trabajar con fechas en nuestros sistemas espero que sirva a alguien saludos