entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

3votos

Creación de clase para tratamiento de BBDD

Según consejo de @carlossevi quiero proceder a la creación de una clase para el tratamiento de nuestro código PHP con nuestra base de datos SQL Server. Para ello he comenzado a leer por la siguiente documentación:

http://danielbrena.blogspot.com/2014/01/crear-una-clase-en-php-para-el-manejo.html

El asunto es que cuando veo la codificación PHP que tiene en el centro de la página sobre fondo negro no entiendo algunas cosas. Por qué hace unas funciones que no hacen nada? Ni reciben parámetros ni nada?

Me refiero a las:

abstract protected function get();
abstract protected function set();
...

Después hace la función de abrir conexión y cerrar las cuales entiendo perfectamente así como la función de ejecutar una consulta y obtener resultados de consulta pero esas get(), set(), edit() y delete() no entiendo qué son ni cual es su función.

También me gustaría saber cuando hace

$this->conexion = new (en mi caso sería sqlsrv_connect) mis datos

Qué quiere decir el $this->conexion? this hace alusión a la clase y conexion a la variable conexion de la clase?
Lo siento si parezco un ignorante pero nunca había hecho esto antes.

2 Respuestas

3votos

ankeorum Puntos7210

Después de estar casi toda la mañana para hacerlo creo que tengo ya algo claro el asunto:

Primero he quedado un fichero config.php donde almaceno todos los datos generales sobre la conexión, este fichero quedaría tal que así:

<?php

//Database config values

//Server
$host='192.168.1.12';

//User
$user='username';

//Password
$password='password';

//Database
$db='database';

//Database system to use
$dbType='sqlsrv';
?>

Ese fichero sería el general de configuración, una vez creada la clase completa con los 3 ficheros a usar este nos valdría para cambiar de base de datos, usuario, contraseña o tipo de base de datos de forma rápida y eficaz. Además es escalable para cualquier sistema que usemos.

En segundo lugar tenemos un archivo conf.class.php que nos da la configuración concreta de la clase, este fichero sería tal que así:

<?php

Class Conf{
   private $_domain;
   private $_userdb;
   private $_passdb;
   private $_hostdb;
   private $_db;
   private $_dbType;

   private static $_instance;

   private function __construct(){
      require 'config.php';
      $this->_domain=$domain;
      $this->_userdb=$user;
      $this->_passdb=$password;
      $this->_hostdb=$host;
      $this->_db=$db;
      $this->_dbType=$dbType;
   }

   private function __clone(){ }

   private function __wakeup(){ }

   public static function getInstance(){
      if (!(self::$_instance instanceof self)){
         self::$_instance=new self();
      }
      return self::$_instance;
   }

   public function getUserDB(){
      $var=$this->_userdb;
      return $var;
   }

   public function getHostDB(){
      $var=$this->_hostdb;
      return $var;
   }

   public function getPassDB(){
      $var=$this->_passdb;
      return $var;
   }

   public function getDB(){
      $var=$this->_db;
      return $var;
   }

   public function getDBType(){
     $var=$this->_dbType;
     return $var;
   }

}
?>

Por último y principal tenemos los controles concretos de la base de datos, ejecución de consultas, búsqueda de filas, etc. este fichero lo he llamado db.class.php y quedaría más o menos así, a falta de incluir muchas más funciones de sqlsrv como por ejemplo sqlsrv_errors para control de errores, etc;

<?php

/* Class for managing database */
Class Db{

   private $server;
   private $user;
   private $password;
   private $database;
   private $type;
   private $link;
   private $connstring;
   private $stmt;
   private $array;

   private static $_instance;

   /*Construct function private to avoid creating by new instances*/
   private function __construct(){
      $this->setConexion();
      $this->conectar();
   }

   /*Method for setting the paremeters of the connection*/
   private function setConexion(){
      $conf = Conf::getInstance();
      $this->server=$conf->getHostDB();
      $this->database=$conf->getDB();
      $this->user=$conf->getUserDB();
      $this->password=$conf->getPassDB();
      $this->type=$conf->getDBType();
   }

   /*We avoid clone. Singleton pattern*/
   private function __clone(){ }

   private function __wakeup(){ }

   /*Function that creates, if neccessary, the object. We must call this function to instance the object.*/
   public static function getInstance(){
      if (!(self::$_instance instanceof self)){
         self::$_instance=new self();
      }
      return self::$_instance;
   }

   /*Connect with database.*/
   private function conectar()
   {
       $this->connstring = array( "Database"=>"mplc_db", "UID"=>"php_user_rw", "PWD"=>"sh1rehampton");
       //$this->connstring = '"UID" => '.$this->user.', "PWD" => '.$this->password.', "Database" => '.$this->database;

       if ($this->type = 'sqlsrv')
       {
            echo "Database is SQL Server <br >";
            $this->link = sqlsrv_connect($this->server, $this->connstring);
            echo $this->link." <br >";
       }
       else 
       {
           echo "Server is not SQL Server";
       }      
   }

   /*Execute SQL sentence*/
   public function execute_query($sql){
      switch ($this->type){
         case 'sqlsrv':
                echo "Call to function seems to work <br>"; 
                $this->stmt=sqlsrv_query($this->link, $sql);
                break;
         break;
      }
      return $this->stmt;
   }

   /*Get a row from SQL*/
   public function get_row($stmt)
   {
       //echo "Call to function seems to work <br>"; 
       if ($this->type = 'sqlsrv')
       {
           //echo "Call to function seems to work and database is SQL Server<br>"; 
           $this->array=sqlsrv_fetch_array($stmt);
       }
       return $this->array;
   }

}

?>

Bueno esto es todo, creo que finalmente se solucionó el problema aunque me gustaría que los gurús me dieran su opinión @Peter, @Leonardo-Tadei, @carlossevi qué opinión os merece?

SaludoS!

0voto

Leonardo-Tadei comentado

No debiste haberme preguntado ;-)

Yo soy un purista de la POO, y por tanto los ActiveRecord, como el que estás implementando, me parecen una solución siempre inadecuada desde el punto de vista del diseño de una solución Orientada a Objetos. Los ActiveRecord son un antipatrón ámpliamente usado, pero que se use mucho no significa que sea una buena práctica.

De todas formas, si vas a usar ActiveRecord o alguna variante, PHP ya hace esto con su clase PDO, que no solo conecta a MS SQLServer, sino que además provee una capa de abstracción para cualquier DB: http://php.net/manual/en/ref.pdo-sqlsrv.connection.php

Si la clase para la conexión y el ActiveRecord son algo así como un accidente en este software, porque en realidad está pensado como Programación Estructurada, las PDO y su implementación del ActiveRecord deberían servirte.

Si en cambio el diseño es en Objetos, deberías estar pensando en las clases del Modelo que resuelven el problema y depegar la persistencias a algún ORM existente. Acá hemos desarrolla un Mapeador Objeto/Relaciónal que hace persistencia no invasiva y por alcance, que es Software Libre y está disponible en https://github.com/PegasusTech/Persistent Para su funcionamiento interno usa las PDO, la API de Reflection y varias cosas más dismponibles en PHP 5 y superiores. Es un framework de mapeo objeto/relacional que se comporta como un repositorio virtual de Objetos, cuyo uso no implica ni heredar ni tener código que lo referencie en tus class de Modelo.

Tu implementación, desde el punto de vista del código es buena: atributos privados, claridad de intención, singleton, etc. Tal vez sea cuestionable que el constructor no reciba como mensaje los valores de coneción, en vez de tenerlos declarados en variables y que la definición de configuración no sean constantes que use directamente (con lo que la clase Config pasaría a ser innecesaria) y tu singleton está mal aplciado a la clase de configuración, ya que lo que tenés que garantizar que exista una sola vez es la conexión, y no sus valores para hacerla.

Desde el punto de vista de la implementación de la POO, no quisiera que esto fuera parte de mi código :-(

Lo siento de veras si lo que te digo suena un poco duro, la intención es solamente compartir mi punto de vista y sus motivos. De hecho cuando vi para dónde iba tu pregunta me abstuve de participar para no ser el viejo gruñón del grupo ;-)

Saludos cordiales!

0voto

ankeorum comentado

En primer lugar gracias por compartir tu conocimiento y tu tiempo, en segundo lugar siéntete libre al 200% de decir lo que quieras en mis post que lejos de enojarme tomaré buena nota ya que cuando alguien sabe más que uno lo más sabio es callar y escuchar bien para poder mejorar y aprender.

Decirte que tomaré nota de lo que comentas e intentaré aprender, por ahora no tengo nada de idea de PDO ni POO ni ORM ni varias cosas que has puesto pero si eres una persona paciente estoy dispuesto a aprender todo lo que puedas enseñarme. Voy a leer el código que has puesto que supongo que no entenderé porque no sé nada de POO pero bueno, por algo se empieza.

De nuevo mil gracias y sigue así porque es la mejor forma de aprender. Un abrazo

SaludoS!

0voto

Leonardo-Tadei comentado

ankeorum, la programación se basa en varios paradigmas, es decir, en varias formas de abordar un problema. Tenés por ejemplo la Programación EStructurada, la Programación Lógica, la Programación Funcional, la Programación Orientada a Objetos, la Programación Orientada a Aspectos (que trabaja sobre la Programación Orientada a Objetos) y algunas más.

Algunas metodologías son mejores para reselver ciertos tipos de problemas, otras son más generales. Hay lenguajes que se craron para implementar algún paradigma de programación, y por lo tanto usarlos para otros paradigmas es difícil o implica violar principios de esa forma de programación.

PHP es un lenguaje híbrido que soporta varios paradigmas, lo que implica ser muy cuidadoso cuando se programa porque esta versatilidad implica que se pueden violar algunos proncipios. Por ejemplo para aplicar Programación Orientada a Objetos (POO), PHP permite definir atributos públicos, y los lenguajes puros para POO no tienen siquiera esa capacidad, porque esto viola el principio de encapsulamiento propio de la POO.

Como vos implementaste una clase, supuse que estás usando POO, ya que ese concepto es propio solo de este paradigma de programación. Ahora me comentás que es un concepto que no manejás... y para todo velero sin puerto, cualquier viento es viento a favor.

Por otra parte, si vas a echar un vistazo a mi código, te sugeríria que mires primero los ejemplos (y que elabores los tuyos y si querés enviámelos para ampliar con ejemplos de uso), para así comprender mejor qué es lo que hace el ORM, independientemente de cómo lo hace, que es algo que no es necesario al principio. Una de las virtudes de la POO es que se puede usar código complegísimo hecho por otros sin tener siquiera que leerlo, y mirando solo las interfaces y métdos públicos que tiene.

Si ttenés dudas, consultas o sugerencias, ya sabes por dónde andamos.

Saludos!

3votos

carlossevi Puntos63580

Efectivamente $this-> hace referencia al objeto miembro de la clase que estás definiendo y lo que viene después puede ser variables o métodos propios de la clase.

En el caso que mencionas se hace referencia a una variable propia de la clase que está definida más arriba:

private $conexion;

Sobre esa variable almacena un nuevo objeto de conexión mysqli, en tu caso tendrás que almacenar un objeto de conexión a MS SQL.

Respecto a las líneas que no sabes lo que hacen son definiciones de métodos abstractos. A grandes rasgos son métodos que se nombran pero no se definen en este momento sino que serán definidas en la definición de futuras clases que hereden de esta.

En el enlace que te pongo hay un ejemplo que se entiende bastante bien pero necesitas una pequeña base de programación POO en PHP.

0voto

ankeorum comentado

Muchas gracias voy a leerlo. Se me acumula la literatura jajaajaj

P.D.: No busquéis en google POO sólo, buscadlo acompañado de PHP o algo más o no os gustarán los resultados... o sí, nunca se sabe...

0voto

ankeorum comentado

Acabo de leerme el libro de PHP que me recomendaste y el documento de ayuda de PHP sobre abstracción de clases y la verdad que no me ha quedado muy claro como crear una clase que controle lo relacionado con las consultas y sentencias SQL Server. Supongo, a grandes rasgos, que lo tengo que hacer es un sólo documento donde, explicado "bastamente" lo que yo haga sea renombrar las funciones originales de sqlsrv por otras que yo use más amigables, en el futuro en caso de que de nuevo cambie el soporte en versiones PHP futuras sólo tendría que cambiar las llamadas en la clase y no en todo el sitio/proyecto.

Creo que he entendido que eso es lo que tengo que hacer, lo que no sé es cómo hacerlo...

Sabéis alguna parte donde pueda documentarme? O me podéis poner un ejemplo?

0voto

carlossevi comentado

Lo has entendido perfectamente.

Te puedo poner un par de links con códigos y ejemplos pero he de remarcar que no las he utilizado nunca.

http://redinkdesign.co/blarg/ms-sql-class/
http://snipplr.com/view/12537/oop-mssql-database-class/

Por otro lado te adelanto que hay muchos frameworks para trabajar con PHP que ya incluyen este tipo de clases además de otras para trabajar con ficheros, fechas, formularios, cache y un largo etc. Además facilitan la implentación de patrones para estructurar el código, utilizar plantillas y hacer que tu aplicación sea más fácilmente mantenible de cara a futuras actualizaciones.

Estos frameworks tienen una curva de aprendizaje más dura aunque una vez los controlas te facilitan mucho las tareas acortando tiempos de desarrollo además de implementar por defecto muchas medidas de seguridad para evitar que tu aplicación sea vulnerable. Por si quieres buscar información al respecto yo acoscumbro a utilizar CodeIgniter aunque también lo he hecho con Symfony que es más popular y potente (y ojo, también complicado). Te dejo una lista: http://www.webhostingreviewboard.com/development/top-ten-best-php-frameworks-for-2014/

0voto

Peter comentado

@ankeorum, por favor publica tus comentarios como comentarios y no como respuestas.

Gracias :)

0voto

ankeorum comentado

Bien, después de mucho indagar y jugar con frameworks y tal hemos decidido que la solución más rápida y escalable va a ser la creación de una clase propia con la que tratemos las bbdd. A partir de ahí cuando nos ocurra de nuevo este problema lo solucionaremos en 5 minutos como dijo @carlossevi.

El problema surge de que no tengo ni idea de cómo meterle mano a esto y no encuentro mucha documentación en San Google. Alguna idea?

1voto

ankeorum comentado

Bueno, una vez metidos en la faena tenemos lo siguiente:

abstract class useDB
{
    private static $db_host = "southern";
    private static $db_user = "php_user_rw";
    private static $db_password = "sh1rehampton";
    protected $db_name = "mplc_db";
    protected $query;
    protected $rows = array();
    private $conn;
    public $msg = "Succesfully connected to database";
    public $upload_loc = "D:\\\\uploads\\\\";

    abstract protected function get();
    abstract protected function set();
    abstract protected function edit();
    abstract protected function delete();

    public function open_connection()
    {
        $conection_info = '"Database"=>"".self::$database."","UID"=>"".self::$dbusername."","PWD"=>"".self::$password.""';
        $this->conn = new sqlsrv_connect(self::$db_host, $connection_info);
    }

    public function close_connection()
    {
        $this->conn->sqlsrv_close();
    }
    protected function execute_single_query($result)
    {
        $this->open_connection();
        $this->query = sqlsrv_query(self::$conn, $result);
        $this->close_connection();
    }
    protected function get_results_from_query($result)
    {
        $this->open_connection();
        $stmt = $this->conn->sqlsrv_fecth(self::$conn, $result);
        while ($this->rows[] = $stmt->sqlsrv_fetch_array(self::$conn, $result, SQLSRV_FETCH_NUMERIC));
        $stmt->close();
        $this->close_connection();
        array_pop($this->rows);
    }

}

Ya tenemos algo con lo que empezar, lo que básicamente quiero hacer es "renombrar" las funciones básicas de sqlsrv para así tenerlas con nuestra propia nomenclatura en una clase, una vez hecho eso si el día de mañana tenemos otro cambio de controlador como el que se ha producido sólo tenemos que cambiar las funciones en una página PHP.

Qué opináis? Es factible? Voy descaminado?

0voto

Peter comentado

Puse tu respuesta como comentario, porque no es una respuesta. Por favor para preguntas nuevas, abre preguntas nuevas y selecciona una respuesta como correcta en caso de que lo sea.

Gracias.

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta