Arquitectura Modelo – Vista – Controlador

Posted Posted by admin in Tutoriales     Comments No Comments
Dic
16

El MVC (Modelo – Vista – Controlador) es un patrón utilizado continuamente  en la programación Web, a menudo utilizando un Framework que facilite el trabajo. A continuación vamos a ver un ejemplo claro de modificación de una tabla de nuestra base de datos utilizando este patrón:

Empezaremos explicando brevemente en qué consiste:

El modelo gestiona el acceso con la base de datos. Es el encargado tanto de hacer consultas como actualizaciones de esta, implementando los privilegios de acceso.

Envía a la vista, la información que se le ha solicitado para que sea la vista la encargada de mostrarla al usuario. Tanto la petición de obtener los resultados de una consulta, como de actualización de la base de datos, se recibe del controlador, por lo que para mostrar una vista con los datos devueltos, también se utilizará el controlador.

 

El controlador es una sección de código que hace de intermediario entre el “modelo” y la “vista”, encargándose además de proveer de cierta seguridad a la aplicación.

Funciona respondiendo a los eventos accionados por el usuario y envía peticiones al modelo, que será el encargado de interactuar con la base de datos o archivos.

Una vez el modelo devuelve al controlador los correspondientes datos, en función de la petición solicitada, será el controlador el que haga la llamada a la vista, enviándole los datos devueltos por el modelo.

La vista, en definitiva, es la interfaz de usuario, que muestra los datos obtenidos del modelo. A través de la vista, el usuario puede generar diferentes eventos que los recibirá el controlador, y este llamará al modelo para devolver los datos solicitados a la vista de nuevo.

Gestión de artículos

Para que este artículo no se haga demasiado extenso, partiremos suponiendo que se tiene un mínimo conocimiento sobre HTML y CSS para la creación de vistas, y PHP que será el lenguaje de programación Web utilizado.

A continuación se muestra el proceso de creación y modificación de la tabla artículos. Cada artículo se encuentra asociado a un usuario. A continuación se muestra el diagrama entidad – relación:

entidad - relación

Para hacer más fácil el seguimiento del proceso, vamos a empezar creando nuestro controlador.

A continuación expongo un ejemplo de controlador:

Incluimos el archivo de vistas y modelo, y en la clase del controlador, declaramos las variables privadas modelo y vistas, que las utilizaremos para llamar a la instancia que debemos de haber creado con dichas variables.

A continuación, recibimos el valor de la variable do, y en función del valor que se reciba, entraremos en el caso definido para tal acción del condicional “switch”.

<?php
    include_once("models/users_model.php");
    include_once("views/users_views.php");
    class ControllerAdmin{
       private $users_model, $users_view;
       public function ControllerAdmin() {
          $this->users_model = new Users_model();
          $this->users_views = new Users_views();
       }
    function main(){
       if(!isset($_REQUEST['do'])){
          $do="showLogin";
       }else{
          $do=$_REQUEST['do'];
    }
    switch($do){
       case "viewArticles": // Vista general de artículos
          if($acceso==1){
             $this->viewArticles();
          }else{
             $this->users_views->loginForm();
          }
          break;
       case "editArticle":
          if($acceso==true){
             $this->viewEditArticle();
          }else{
             $this->users_views->loginForm();
          }
          break;
       case "showAltaArticle":
          $this->viewEditArticle("newArticle");
          break;
       case "searchArticles":
          $this->searchArticles();
          break;
       case "newArticle":
          $this->newArticle();
          break;
    }

Los siguientes métodos, realizan determinadas tareas, llamando al modelo y a la vista en función de la tarea que se esté realizando.
 
/**
* Parámetros: puede recibir una variable error para mostrarlo en la vista. si no se recibe está vacía
* Función: muestra la vista de los artículos
*/
          function viewArticles($error=""){
       $data = $this->users_model->showArticles();
       $this->users_views->viewAdminArticles($data,$error);
    }
    function viewEditArticle($error=""){
       if ($error == "newArticle"){
          $error="";
          $titHead = "Nuevo artículo";
          $a = unserialize($_COOKIE['SADSD']);
          $autores = $this->users_model->showUsers();
          $this->users_views->viewEditArticles(0, $autores, $titHead, $a['id'], $error);
       }else{
          $titHead = "Administración de artículos";
          if(isset($_REQUEST['editar'])){
             $data = $this->users_model->select("articulos", "id_art", $_REQUEST['id_art']);
             $autores = $this->users_model->showUsersAdmin();
             $this->users_views->viewEditArticles($data, $autores ,$titHead, $error);
          }else if(isset($_REQUEST['eliminar'])){
                //Si en la vista se ha pulsado el boton eliminar ejecuta el modelo eliminaUsuarios
                $id_art=$_REQUEST["id_art"];
                $sw=$this->users_model->delete("articulos", "id_art", $_REQUEST['id_art']);
                switch($sw){
                   case 1:
                      $this->viewArticles();
                      break;
                   case 2: 
                      $this->viewArticles($error);
                      break;
                }
             }else if(isset($_REQUEST['actualizar'])){
                $sw = $this->users_model->actualizaArticulos();
 // Comprueba si no se ha ejecutado correctamente, en este caso hace una consulta para obtener los datos 
 // del usuario y cambia la variable sw para mostra la vista de perfil (viewPerfilUsers) con el error.

                if ($sw != 1 ){
                   $data = $this->users_model->select("articulos", "id_art", $_REQUEST['id_art']);
                   $sw=2;
                }
                switch($sw){
                   case 1: $this->viewArticles();
                   break;
                   case 2: 
                      $autores = $this->users_model->showUsers();
                      $this->users_views->viewEditArticles($data,$autores,$titHead,"No se han podido actualizar los datos");
                   break;
                } 
             }
          }
       }
    }
/**
* Parámetros: $error: permite la posibilidad de recibir un error de búsqueda, que se mostrará en la vista
* Función: genera la consulta para mostrar los artículos según el filtro indicado de texto
*/
    function searchArticles($error=""){
       $data = $this->users_model->searchArticles();
       if ($data == null)
          $error = "No se encuentran coincidencias";
       $this->users_views->viewAdminArticles($data,$error);
    }
/**
* Parámetros: $error: permite la posibilidad de recibir un error de búsqueda, que se mostrará en la vista
* Función: genera la consulta para insertar un nuevo artículo en la BD
*/
    function newArticle($error=""){
       $sw = $this->users_model->insertArticle();
       if ($sw == 1)
          $this->viewArticles();
       else
          $this->viewArticles("No se ha podido crear el artículo");
       }
}
?>

El código anterior, será el encargado de controlar el modelo y las vistas, formando vistas según el evento seleccionado, obteniendo los datos de la base de datos a través del modelo. A continuación, vamos a ver el archivo del modelo.

En nuestro ejemplo, el modelo no es el encargado de hacer las consultas sobre la base de datos, si no que prepara las consultas y las envía a una capa intermedia entre el modelo y la base de datos, a la que se denomina capa de abstracción, la cuál tendrá los métodos encargados de recibir la consulta y ejecutarla.

Lo primero que debe de contener, es la inclusión de los archivos de configuración, en el que se guardará en variables, los datos de acceso a la base de datos: usuario, contraseña, nombre de base de datos y nombre del servidor. Además, se incluirá el archivo de la clase “consulta”, que será la capa de abstracción de nuestro sistema.

El código del modelo será el siguiente:

<?php
   include_once ('class/consult.php');
   include_once ($_SERVER['DOCUMENT_ROOT']."/Servidores/TheBares/configuration.php");

   class Users_model{

   private $consulObj;
   private $configObj;
   function Users_model() {
      $configObj = new JConfig(); //Instancio la clase JConfig del archivo de configuracion
      $dbtype = $configObj->dbtype; //Obtengo el valor del gestor de bases de datos
      switch ($dbtype) {
         case "mysqli": //Base de datos MySql
            $this->consulObj = new classConsultMysqli;
            break;
      }
   }
   function showArticles(){
      $data=$this->consulObj->selectU("SELECT id_art, nombre, descripcion, usuarios.nombre_us, usuarios.mail, fecha_creacion FROM articulos INNER JOIN usuarios ON usuarios.usuario = articulos.autor ORDER BY nombre asc;");
      return $data;
   }
   function showDataArticle($id){
      $data=$this->consulObj->select("SELECT id_art, articulos.nombre, articulos.descripcion, usuarios.nombre_us, fecha_creacion, code, usuarios.mail FROM articulos INNER JOIN usuarios ON usuarios.usuario = articulos.autor WHERE id_art LIKE ".$id.";");
      return $data;
   }
   function showUsersAdmin(){
      $data=$this->consulObj->selectU("select * from usuarios where rol=2");
      return $data; 
   }
   function searchArticles(){
      $text = $_REQUEST['texto'];
      $query = "select id_art, nombre, descripcion, usuarios.nombre_us, usuarios.mail, fecha_creacion from articulos INNER JOIN usuarios ON usuarios.usuario = articulos.autor where nombre LIKE '%".$text."%' OR descripcion LIKE '%".$text."%' OR autor LIKE '%".$text."%' OR fecha_creacion LIKE '%".$text."%';";
      $data = $this->consulObj->selectU($query);
      return $data;
   }
 /**
 * Parameters: todos los atributos de la tabla articulos
 * Function: actualiza los datos del articulo
 */
  function actualizaArticulos(){
     $id=$_REQUEST["id_art"];
     $nombre=$_REQUEST["nombre"];
     $descrip=$_REQUEST["descrip"];
     $autor=$_REQUEST["autores"];
     $code=$_REQUEST["code"];

     $ok=$this->consulObj->update("update articulos set nombre='$nombre', descripcion='$descrip', autor='$autor', code='$code' where id_art LIKE '$id'"); 
     return $ok;
  }
  function insertArticle(){
     $id = $_REQUEST["id"];
     $nombre = $_REQUEST["nombre"];
     $descrip = $_REQUEST["descrip"];
     $code = $_REQUEST["code"];
     $ok = $this->consulObj->insert("insert articulos set nombre='$nombre', descripcion='$descrip', autor='$id', code='$code'");
     return $ok;
  }} ?>

Como podemos observar, la clase modelo es básica, por lo que un problema al que deberemos de enfrentarnos, es el de intentar reutilizar el máximo número de líneas de código para hacer nuestro programa lo más sencillo y escalable posible.

Por último, indicaremos el código escrito en nuestra capa de abstracción, la cuál será la que interactúe con nuestra base de datos.

<?php
    include ($_SERVER['DOCUMENT_ROOT']."/Servidores/TheBares/configuration.php");
    class classConsultMysqli{
       private $conexdb;
       private $config;

       // Método que crea una conexión a la base de datos
       private function conecta() {
          $config = new JConfig();
          $host = $config->host;
          $user = $config->user;
          $password = $config->password;
          $db = $config->db;
          $this->conexdb = new mysqli($host,$user,$password,$db);
       }

       // Método que cierra la conexión con la base de datos
       private function desconecta(){
          $this->conexdb->close(); 
       }
       function selectU($query){
          $this->conecta();
          $resul= $this->conexdb->query($query);
          if ($this->conexdb->affected_rows <= 0){
             $resul = null; //NO SE HA PODIDO EJECUTAR LA SENTENCIA
          }
          $this->desconecta();
          return $resul;
       }
       function insert($query){
          $this->conecta();
          $this->conexdb->query($query);
          if (count($this->conexdb) > 0){
             $resul = 1; //INGRESO CORRECTO
          }else{
             $resul = 2; //NO SE HA PODIDO EJECUTAR LA SENTENCIA
          }
          $this->desconecta();
          return $resul;
       }
       function update($query){
          $this->conecta();
              //Ejecución de la consulta
          $this->conexdb->query($query);
          if ($this->conexdb->affected_rows > 0){
             $resul = 1; //ACTUALIZACIÓN CORRECTA
          }else{
             $resul = 2; //NO SE HA PODIDO EJECUTAR LA SENTENCIA
          }
          $this->desconecta();
          return $resul;
       }
       function delete ($query){
          $this->conecta();
          $this->conexdb->query($query); 
          if (count($this->conexdb) > 0){
             $resul = 1; //ELIMINADO CORRECTO
          }else{
             $resul = 2; //NO ELIMINADO
          }
          $this->desconecta();
          return $resul;
       }
   }
?>

En esta clase, como hemos podido observar, recibimos un parámetro ($query), el cuál contendrá una cadena de texto con la consulta ya formada que se vaya a ejecutar, devolviendo un parámetro al modelo y a su vez al controlador, que será el encargado de mostrar una u otra vista dependiendo de si el resultado de la ejecución ha tenido éxito.

Las vistas no se exponen porque estas dependerán exclusivamente del proyecto para el que vayamos a desarrollar.
La estructura seguida, es una clase “vistas” en la que encontraremos diferentes métodos, a los cuáles son los que se llaman desde el controlador para mostrar la vista correspondiente, en la que incluiremos el archivo de la vista deseado.

Post comment