sábado, 10 de septiembre de 2022

CRUD POO PHP MVC (PROYECTO STAR CRUD PARTE 1)

 

El concepto CRUD está estrechamente vinculado a la gestión de datos digitales. CRUD hace referencia a un acrónimo en el que se reúnen las primeras letras de las cuatro operaciones fundamentales de aplicaciones persistentes en sistemas de bases de datos:

  •         Create  (Crear registros)
  •         Read     (Leer registros)
  •         Update (Actualizar registros)
  •         Delete  (Borrar registros)

En pocas palabras, CRUD resume las funciones requeridas por un usuario para crear y gestionar datos. Varios procesos de gestión de datos están basados en CRUD, en los que dichas operaciones están específicamente adaptadas a los requisitos del sistema y de usuario, ya sea para la gestión de bases de datos o para el uso de aplicaciones.

El proyecto STAR CRUD, es un ejercicio de programación completo para crear un sistema CRUD que gestione una base de datos donde vamos a poder guardar, editar o eliminar un registro de todos los planetas existentes en el universo de ficción de la saga STAR WARS.

El sistema está programado con PHP siguiendo el paradigma de programación orientada a objetos POO y, siguiendo el patrón de diseño de software MVC (Modelo Vista Controlador).

El sistema dispondrá también de un sistema de registro de usuarios y login para poder entrar al sistema, y la base de datos y su tratamiento está construida con Mysql y XAMPP.

Para la parte de estilos en cascada usaremos Bootstrap 5. 


ESTRUCTURA DEL PROYECTO

REGISTRO Y LOGIN CON PHP POO (AÑADIENDO CLASES A MI MODELO)

Creamos la siguinete estructura de carpetas en la carpata raiz del proyecto:


Creamos los archivos styles.css y scripts.js en las carpetas CSS y JS respectivamente

Creamos el archivo de inicio del proyecto index.php


DEPENDENCIAS

Vamos a enlazar nuestros estilos css y el JavaScript desde el index.php

Usaremos la fuente oficial de STAR WARS, añadiéndola al proyecto mediante su cdn:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>STARS CRUD</title>
    <link href="https://allfont.net/allfont.css?fonts=star-jedi" rel="stylesheet" type="text/css" />
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
 
   
<script src="js/scripts.js"></script>
</body>
</html>

 

En nuestro archivo CSS haremos un sencillo reset  y estableceremos la fuente por defecto:

  html {
    box-sizing: border-box;
    font-family: 'Star Jedi', arial;
    font-size: 16px;
  }
 
  *, *:before, *:after {
    box-sizing: inherit;
  }
 
  body, h1, h2, h3, h4, h5, h6, p, ol, ul {
    margin: 0;
    padding: 0;
    font-weight: normal;
  }
 
  ol, ul {
    list-style: none;
  }
 
  img {
    max-width: 100%;
    height: auto;
  }

 

Para ver como nos queda haremos un pequeño hola mundo con un h1 en el index:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>STARS CRUD</title>
    <link href="https://allfont.net/allfont.css?fonts=star-jedi" rel="stylesheet" type="text/css" />
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <h1><b>Hola STARS CRUD<b></h1>
 
   
<script src="js/scripts.js"></script>
</body>
</html>




Añadiremos el cdn de bootstrap y Font awesome parausar iconos,para usar fontawesome hay que registrarse y recibir el script:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>STARS CRUD</title>
    <!--Bootstrap cdn-->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <!--Fontawesome cdn-->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/fontawesome.min.css" integrity="sha384-X8QTME3FCg1DLb58++lPvsjbQoCT9bp3MsUU3grbIny/3ZwUJkRNO8NPW6zqzuW9" crossorigin="anonymous">
    <!--Starwars Font cdn-->
    <link href="https://allfont.net/allfont.css?fonts=star-jedi" rel="stylesheet" type="text/css" />
    <!--Mis estilos-->
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <h1><b>Hola STARS CRUD<b><i class="fa-solid fa-file-code"></i></h1>
 
<!--Font awesome personal js-->
<script src="https://kit.fontawesome.com/1e88d8726f.js" crossorigin="anonymous"></script>
<!--Bootstrap js-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<!--Mis scripts JS-->  
<script src="js/scripts.js"></script>
</body>
</html>

Por ultimo añadiremos nuestro favicon al sitio, tenemos el archivo en assets

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" type="image/jpg" href="assets/favicon.ico"/>

 De momento es todo si necesitamos algo más lo instalaremos más adelante.

MAQUETACIÓN DEL INDEX.PHP

Vamos a crear un primera maquetación usando Bootstrap para nuestro index:

NOTA. Para  cambiar estilos bootstrap debes eliminar la clase bootstrap y poner una propia

CREANDO EL NAVBAR

<body>
 <!--Navbar-->  
<nav class="navbar navbar-expand-sm bg-dark navbar-dark fixed-top">
  <div class="container-fluid">
    <a class="brand" href="#">STARS CRUD</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collapsibleNavbar">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse myNav" id="collapsibleNavbar">
      <ul class="navbar-nav">
        <li class="nav-item">
          <a href="#">Link</a>
        </li>
        <li class="nav-item">
          <a  href="#">Link</a>
        </li>
        <li class="nav-item">
          <a  href="#">Link</a>
        </li>
      </ul>
    </div>
  </div>
</nav>
<!--end navbar-->

 CLASES CSS PARA EL HEADER Y NAV

 /*HEADER AND NAV CLASSES*/
  .brand {
    color: red;
    text-decoration: none;
    font-weight: bolder;
    font-size: 1.5rem;
    opacity: 1;
  }
 
  .brand:hover {
    transition: 0.8s ease all;
    color: var(--secondary)
 
  }
 
 
  .navbar-nav {
    padding-left: 50px;
  }
 
  .nav-item {
    padding-left: 20px;
  }
 
  .nav-item  a{
    color:red;
    text-decoration: none;
    font-weight: bolder;
    font-size: 1rem;
  }
 
  .nav-item  a:hover{
    transition: 0.8s ease all;
    color: var(--secondary)
  }
 
  .custom-toggler .navbar-toggler-icon {
    background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,0,0, 1)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E");
  }
   

 

CREANDO LA SECCIÓN HEROE

<!-- Hero -->
<div class="p-5 text-center bg-image rounded-3 heroe">
  <div class="mask">
    <div class="d-flex justify-content-center align-items-center">
      <div class="text-white heroe-title">
        <h1 class="mb-3">STAR CRUD</h1>
        <h4 class="mb-3">May the 4th be with you</h4>
        <a class="btn btn-outline-light btn-lg" href="#!" role="button">Do or do not, there is no try</a>
      </div>
    </div>
  </div>
</div>
<!-- Hero -->

CLASES PARA LA SECCIÓN HEROE

 /*------HEROE CLASSES-----*/
  .heroe {
    background-image: url("../assets/mustafar.jpg");
    background-position: center;
    background-size: contain;   /*Hace que la imagen de fonde sea responsiva, cover no*/
    background-repeat: no-repeat;
    background-color: rgba(0, 0, 0, 0.6);
    height: 100vh;
  }
 
  .heroe-title {
    padding-top:20%;
  }
 
  @media(min-width: 1400px) {
    .heroe {
      background-size: cover;
    }
  }
 
  @media(min-width: 400px) {
    .heroe {
      background-size: cover;
    }
  }
 

 SECCIÓN FOOTER

<!--footer-->
<footer clas="footer mt-auto py-3 bg-darck">
<div class="container">
    <div class="row">
      <div class="col-sm line icon-f"><i class="fa-brands fa-facebook-f fa-3x"></i></div>
      <div class="col-sm line icon-y"><i class="fa-brands fa-youtube fa-3x"></i></div>
      <div class="col-sm line icon-i"><i class="fa-brands fa-instagram fa-3x"></i></div>
    </div>
</div>
</footer>

 

CLASES PARA EL FOOTER

 /*------FOOTER CLASSES-----*/
 
 footer {
 /*------FOOTER CLASSES-----*/
 
 footer {
  width: 100%;
 
  position: absolute;
  bottom: 0;
  left: 0;
 }
 
.footext {
  color: red;
}
 
 
.icon-f,.icon-i, .icon-y {
  text-align: center;
  padding: 2%;
}
 
.icon-f i {
  color: #3b5998;
}
 
.icon-y i {
  color: #c4302b
}
 
.icon-i i {
  color: #3f729b;
}

 

BBDD

CREANDO LA BASE DE DATOS

Vamos a crear la base de datos del proyecto como nuestra aplicación va a disponer de un sistema de login y registro, lo primero que necesitaremos será crear una tabla para almacenar a nuestros usuarios, posteriormente crearemos la tabla que contendrá los planetas del universo star wars (no todos), y deberemos crear una tabla catálogo con las regiones conocidas hasta el momento, ya que esta información es contante. De forma que cuando queramos crear un planeta podamos seleccionar a qué región pertenece desde un select.

Las regiones que forman el universo star wars del canon son:

  • Regiones desconocidas
  • Borde medio
  • Borde exterior
  • Space Sauvage
  • Space Hutt
  • Zona de expansión
  • Marco interior
  • Colonias
  • Mundos del núcleo
  • Más allá del laberinto Rishi

TABLA USUARIOS

CREATE DATABASE starDB;
USE starDB;
 
CREATE TABLE IF NOT EXISTS users (
    id int(11) NOT NULL AUTO_INCREMENT,
    username varchar(30) NOT NULL,
    email varchar(30) NOT NULL,
    password varchar(30) NOT NULL,
    PRIMARY KEY (id),
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3;  
 
CREATE TABLE planetas(
   
)ENGINE= MyISAM CHARSET=utf8;

 

TABLA PLANETAS

CREATE TABLE IF NOT EXISTS planets (
    name varchar(50) NOT NULL,
    description varchar(450) NOT NULL,
    region varchar(30) NOT NULL,
    system VARCHAR(30) NOT NULL,
    habitants VARCHAR(30),
    capital city VARCHAR(30),
    PRIMARY KEY (name),
    FULLTEXT INDEX buscador (
    name,
    nombre ASC,
    region ASC,
    system ASC,
   )
)ENGINE= MyISAM CHARSET=utf8
;

 

TABLA CATÁLOGO regions

-- catalog table regions
CREATE TABLE regions (
    regionName VARCHAR(30) NOT NULL,
    PRIMARY KEY (regionName)
)ENGINE= MyISAM CHARSET=utf8;
 

 PRECARGA DE LA TABLA CATÁLOGO regions

INSERT INTO regions (regionName) VALUES
('Regiones desconocidas'),
('Borde medio'),
('Borde exterior'),
('Space Sauvage'),
('Space Hutt'),
('Zona de expansión'),
('Marco interior'),
('Colonias'),
('Mundos del núcleo'),
('Más allá del laberinto Rishi'
);

 

PRECARGA DE LA TABLA planets

INSERT INTO planets(name,
description,
imgURL,
region,
system,
habitants,
capitalCity
 ) VALUES
 ("Coruscant",
"El sueño de los cosmopolitas: una inmensa gran ciudad cubre este planeta del corazón de la galaxia (sus coordenadas de navegación son 0-0-0).
 Coruscant es la capital gubernamental y sede de la República, del Senado Galáctico y del Consejo Jedi. Algunos de sus edificios tienen kilómetros
 de altura y entre ellos, circulan naves de todo tipo a diferentes niveles.
 Al sur de la ciudad están las Montañas Manarai siempre cubiertas de nieve. Otros puntos de interés turístico de Coruscant son las Grandes Torres,
 los Jardines Botánicos del Domo, el Gran Vestíbulo de Recepciones de un kilómetro de largo, la ciudad subterránea de Dometown, el teatro Grandis Mon,
 el Zoológico Holográfico de Animales Extinguidos, el Museo Galáctico, la Universidad de Coruscant o el Edificio de Operaciones de Seguridad Imperial.
 El espacio que rodea el planeta está defendido por estaciones de batalla orbitales Golan III y una instalación de puertos estelares en órbita.
 Durante los tiempos del Imperio, además, protegían Coruscant dos capas de sofisticados campos de energía.
",
 "planetacoruscant.jpg",
 "Mundos del núcleo",
 "coruscant",
 "Muchos tipos",
 "Ciudad Galáctica"
 )

 

Abrimos nuestro phpmyadmin, creamos la base de datos con el nombre starDB e importamos nuestro archivo starDB.sql en ella:

 






CREANDO EL ARCHIVO dbacces.php (models)


El Archivo dbacces.php forma parte del modelo de nuestra app. En él crearemos la clase modelo DBacces que és una clase especializada en el acceso a la base de datos que centraliza todas las peticiones y sentencias SQL de otras clases modelo.


<?php
/*
Clase DBacces especializada en el acceso a la BAse de DAtos.
Centraliza todas las peticiones de sentencias SQL de otras
clases modelo
*/
 
class DBaccess
 {
 
    //Propiedades privadas que guardan los datos de conexión a la base de datos
    private $db;
    private $host;
    private $user;
    private $password;
    /*La propia clase de gestión de la base de datos guarda los objetos necesarios
      para realizar esta conexión, desde el programa externo que la use.
    */
 
    private $connection; //Conexión real con la base de datos
    private $data; //Datos reales retornados por una consulta exitosa
    private $row; //Una fila de los datos de la consulta realizada
 
    //Constructor de la clase, sireve para crear objetos de la clase
    //debemos pasarle los de conexión.
    function __construct($host, $user, $password, $db) {
        $this->db = $db;
        $this->host = $host;
        $this->user = $user;
        $this->password = $password;
    }
 
    //Método que realiza la conexión a la base de datos con los datos indicados en el constructor
    public function connect_DB()
     {
      $res = true;
     
      $this->connection = mysqli_connect($this->host, $this->user, $this->password, $this->db);
      //$this->connection = mysqli_connect("stardb", "localhost", "root", "");
      //mysqli_set_charset($this->connection, "utf-8");
      if (!$this->connection)
      {
        $res = false;
        die("No se ha podido establecer la conexión con la base de datos. ERROR: ");
      }
 
        return $res;
 
    }
 
    //Desconectar de la base de datos
    public function disconnect_DB()
    {
      if(isset($this->connection))
      {
        mysqli_close($this->connection);
      }
    }
 
    //Función anti ataques SQL-Injection. Esta función retorna los datos que se le pasen
    //filtrando carcteres "peligrosos".
    public function escape_data($data)
    {
      return mysqli_real_escape_string($this->connection, $data);
    }
 
    /*
    Ejecuta un SQL, ya sea SELECT (el retorno del cuál será un dataset o insert), UPDATE o DELETE
    que retorna true o false dependiendo de si ha habido éxito o no.
    Se da por hecho que la conexión se ha realizado previamente, si el SQL es un SELECT, retornará
    el conjunto global de resultados del SELELECT.
    Posteriormente se tendrá que usar la función "consult_row" para obtener la primera fila (o posteriores)
    de resultados
    */
    public function consult_SQL($consult)
    {
      $this->data = mysqli_query($this->connection, $consult);
      if(mysqli_errno($this->connection) != 0)
      {
 
        $res = false;
 
      } else{
 
        $res = true;
 
      }
 
      return $res;
    }
 
    //Función que obtiene la fila de datos de una consulta previamente realizada. Retorna todos los datos
    //de la fila para ser consultados posteriormente con "consult_data"
    public function consult_row()
    {
      $this->row = null;
      if($this->data != null)
      {
 
        $this->row = mysqli_fetch_assoc($this->data);
 
      }
      return $this->row;
    }
 
    /*
    Función que despues de consultar una fila y dado el nombre de un campo de la consulta, retorna la data
    del campo del registro actual. Tanto si el nombre del campo no existe como si ya se han consultado todas
    las filas del resultado, la función devolverá NULL.
    */
    public function consult_data($field)
    {
        $res = null;
        if ($this->row != null)
        {
            $res = $this->row[$field];
        }
        return $res;
    }
 
    //Retorna el número de filas involucradas en una consulta_SQL
    public function affected_rows()
    {
      $res = 0;
      if($this->connection != null)
      {
 
        $res = mysqli_affected_rows($this->connection);
 
      }
      return ($res);
    }
 
    //Elimina la memoria asiciada a la última consulta realizada
    public function consult_close()
    {
      mysqli_free_result($this->data);
    }
 
    //Retorna un eventual mensaje de error producido en una consulta SQL
    public function error_message()
    {
      $res = "";
      if(mysqli_errno($this->connection) != 0)
      {
 
        $res = mysqli_error($this->connection);
 
      }
      return $res;
    }
 
}
?>

 

MODELOS A CONSTRUIR (UNO POR CADA TABLA DE LA BASE DE DATOS)

STAR CRUD tiene 3 tablas users, planets y regios. Pero regions es una tabla catálog que solo vamos a listar y no a modificar por lo que solo tenemos que construir dos modelos Tusers y Tplanets, vamos a nuestra carpeta models y creamos los archivos:



Modelo tusers

Observa que en azul, están los datos que recibiremos de la vista formulario de registro, mientras que en verde están las credenciales necesarias para la conexión a la base de datos que mandaremos desde tcontrol

Propiedades y constructor de la clase Tusers:

<?php
include_once ("dbaccess.php");
 
class Tusers
{
    //Propiedades privadas
    private $username;
    private $email;
    private $password;
    private $img;
 
    private $dba;
 
 
    //Constructor
    function __construct($u_name, $u_email, $u_password,  $host, $user, $password, $db)
    {
        //Adquisición de datos
        $this->username = $u_name;
        $this->email = $u_email;
        $this->password = $u_password;
 
 
    }
 
    //Destructor
    function __destruct()
    {
        if(isset($this->dba))
        {
            unset($this->dba);
        }
    }
}
?>

LA VARIABLE $DBA

Necesitamos crear ahora una variable que guarde una instancia de la clase dbaccess(payload) la podemos llamar como queramos por ejemplo dba (database access) y llamada al método de conexión de la clase dbacces, que guardaremos en la propiedad privada dba:

<?php
include_once ("dbaccess.php");
 
Class Tusers
{
    //Propiedades privadas
    private $username;
    private $email;
    private $password;
    private $img;
    private $dba;
 
    //Constructor
    function __consturctor($u_name, $u_email, $u_password, $u_img)
    {
        //Adquisición de datos
        $this->username = $u_name;
        $this->email = $u_email;
        $this->password = $u_password;
        $this->img = $u_img;
        //Instancia de la clase DBaccess y llamada a su método connect_DB que guardamos en la propiedad dba.
        $v_dba = new DBaccess ($db_name, $server, $user, $pass);
        $this->dba =  $v_dba;
        $this->dba = connect_DB();
    }
 
}
?>

 

Destructor del a clase Tuser

    //Destructor
    function __destruct()
    {
        if(isset($this->dba))
        {
            unset($this->dba);
        }
    }

 Métodos públicos del a clase Tuser

Aquí debemos preguntarnos qué métodos podemos necesitar para gestionar la tabla users dela base de datos, si lo pensamos podemos necesitar las siguientes funciones:

·        Comprobar si un usuario existe

·        Registrar un nuevo usuario

·        Eliminar usuario

·        Método para login

·        Método para hacer logout

Comprobar si un usuario existe. Método user_exists

Este método realiza una consulta a la base de datos usando el método de la clase dbaccess consult_SQL para comprobar si el mail que hemos recibido vía formulario register->gestionavista->tcontrol->hasta llegar aquí.

Consultamos a l abase d edatos si ya existe ese mail, consult_SQL hace la consulta, consult_row consulta las filas devueltas, si el numero de filas es mayor que 0 ese mail existe y la función devuelve true, si no existe la función devuelve false. En el método register que crearemos a continuación usaremos esta función para asegurarnos de que no registramos un usuario con el mismo mail.

   //Comprobar si existe un usuario
   public function user_exists()
   {
       $res = false;
       //consulta usando el método consult_SQL de la clase dbaccess
       if($this->dba->consult_SQL(" SELECT *  FROM users WHERE email = '". $this->email."' "))
       {
           if($this->dba->consult_row() > 0)
           {
               $res= true;
           }
       }
       return $res;
   }

 Registrar un nuevo usuario Método register

   //Registrar usuario usuario
   public function register()
   {
       $res = false;
 
       if(!($this->user_exists()))  //Uso user_exists para ver si existe un user co n ese mail si no cargo el user
 
       {
          if($this->dba->consult_SQL("INSERT INTO users ( username, email, password)VALUES(
               '".$this->dba->escape_data($this->username)."',
               '".$this->dba->escape_data($this->email)."',
               '".$this->dba->escape_data($this->password)."')"))
 
              {
 
                //Alert js para lanzar mensaje y redirigir con js:
                echo "<script language='javascript'>
                          alert('Registered');
                          location='../index.php';
                     </script>";    
 
               //Lo mismo pero con php:
               //$res = "<h2 class='successs'>El usuario ".$this->username." se ha registrado</h2>";
               //redireccionar al index dando tiempo para que se vea el mensaje
               //header("Refresh:4;url=../index.php");
              }
              else
              {
               //Algo ha fallado en la conexión a la base de datos
                echo "<script language='javascript'>
                alert('Something were wrong :(');
                location='../views/register.php';
                </script>";
              }
 
              $res = "<h2 class='successs'>El usuario ".$this->username." se ha registrado</h2>";
       }
 
       echo "<script language='javascript'>
       alert('mail alredy exists, please use another');
       location='../views/register.php';
       </script>";
 
       return $res;
   }


Como podemos ver el método primero comprueba que el mail del usuario a registrar no exista usando el método user_exisis que creamos anteriormente. Si el mail ya existe lanzamos un alert javascript con el mensaje el mail ya existe y redirigimos al usuario de vuelta al register, si no existe creamos una consulta a la base de datos usando el método consult_SQL de la clase dbaccess, y hacemos un INSERT con los datos recibidos vía formulario register->gestionavista->tcontrol->hasta llegar aquí.

En este punto antes de continuar creando los métodos que restan por crear, vamos a poner en práctica nuestro método register. Para ello necesitamos crear los siguientes archivos:

·        Vista register.php: esta vista contendrá el formulario de registro y enviará los datos del usuario a un controlador que llamaremos gestionvista.

·        Controlador gestionvista.php: este controlador recogerá los datos enviados en la vista register.php y creará una instancia de la clase controlador  Tcontrol para usar su método userRegister(), que a su vez creará una instancia de la clase tusers para por fin usar su método register() que es el que insertará el nuevo usuario en la base de datos, usando métodos del modelo dbaccess.

Vamos a ello primero creemos la vista de registro register.php:

VISTA REGISTER.PHP

Vamos a nuestra carpeta views y creamos un nuevo archivo que llamamos register.php


<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" type="image/jpg" href="assets/favicon.ico"/>
    <title>STAR CRUD</title>
    <!--Bootstrap cdn-->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <!--Fontawesome cdn-->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/fontawesome.min.css" integrity="sha384-X8QTME3FCg1DLb58++lPvsjbQoCT9bp3MsUU3grbIny/3ZwUJkRNO8NPW6zqzuW9" crossorigin="anonymous">
    <!--Starwars Font cdn-->
    <link href="https://allfont.net/allfont.css?fonts=star-jedi" rel="stylesheet" type="text/css" />
    <!--Mis estilos-->
    <link rel="stylesheet" href="../css/styles.css">
</head>
<body>
 <!--Navbar-->  
<nav class="navbar navbar-expand-sm bg-dark navbar-dark fixed-top">
  <div class="container-fluid">
    <a class="brand" href="../index.php">STARS CRUD</a>
    <button class="navbar-toggler custom-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collapsibleNavbar">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse myNav" id="collapsibleNavbar">
      <ul class="navbar-nav">
      <li class="nav-item">
          <a href="#"><i class="fa-solid fa-user fa-2x"></i></i></a>
        </li>      
        <li class="nav-item">
          <a href="#">Link</a>
        </li>
        <li class="nav-item">
          <a  href="#">Link</a>
        </li>
      </ul>
    </div>
  </div>
</nav>
<!--end navbar-->
 
<!-- Hero form -->
<!-- Hero -->
<div class="p-5 text-center rounded-3">
  <div class="mask">
    <div class="d-flex justify-content-center align-items-center">
      <!--Form-->
      <form class="myform" name="user_frm" action="../controllers/gestionvista.php" method="post" enctype="multipart/form-data">
      <div class="mb-3">
         <label for="exampleInputname" class="form-label">User name</label>
         <input type="text" name="name_txt" class="form-control" id="exampleInputname" aria-describedby="nameHelp">
       </div>
       <div class="mb-3">
         <label for="exampleInputEmail1" class="form-label">Email address</label>
         <input type="email" name="email_txt" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
         <div id="emailHelp" class="form-text cuote">We'll never share your email with anyone else.</div>
       </div>
       <div class="mb-3">
         <label for="exampleInputPassword1" class="form-label">Password</label>
         <input type="password" name="password_txt" class="form-control" id="exampleInputPassword1">
         </div>
         <button type="submit" name="nuevo_usuario_btn" class="btn btn-dark">Submit</button>
      </form>    
      <!--End form-->
    </div>
  </div>
</div>
<!-- Hero -->
 
<!--footer-->
<footer clas="footer mt-auto py-3 bg-darck">
<div class="container">
    <div class="row">
      <div class="col-sm line icon-f"><i class="fa-brands fa-facebook-f fa-2x"></i></div>
      <div class="col-sm line icon-y"><i class="fa-brands fa-youtube fa-2x"></i></div>
      <div class="col-sm line icon-i"><i class="fa-brands fa-instagram fa-2x"></i></div>
    </div>
</div>
</footer>
 
<!--Font awesome personal js-->
<script src="https://kit.fontawesome.com/1e88d8726f.js" crossorigin="anonymous"></script>
<!--Bootstrap js-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<!--Mis scripts JS-->  
<script src="js/scripts.js"></script>
</body>
</html>

 Como ves se trata de una copia del index, pero en la sección hero, creamos un formulario, con los inputs necesarios, nombre de usuario, mail y contraseña. Lo importante aquí es ver que a los inputs les hemos dado un atributo name, para poder recoger los datos desde el controlador gestionvista. También al submit le hemos dado un name:

         <button type="submit" name="nuevo_usuario_btn" class="btn btn-dark">Submit</button>

 

Para poder saber cuando se ha hecho click en el botón de submit, es decir se ha enviado el formulario. Por ultimo al mismo form, le hemos dado nombre , action que es donde indicamos qué debe hacer el form con la información a donde debe enviarla y en nuestro caso es al controlado gestión vista que vamos a crear a continuación:

<form class="myform" name="user_frm" action="../controllers/gestionvista.php" method="post" enctype="multipart/form-data">

 

Controlador gestionvista.php

Cuando el formularo de la vista register.php envia los datos del usuario lo hace a este archivo gestionvista.php, por tanto este es el controlador de la vista register, lo que vamos a hacer aquí es recoger esos datos para enviarlos al controlador general tcontrol, este tiene la capacidad de comunicarse directamente con cualquier modelo. Ya sea tusers o tplanets, en este caso querremos comunicarnos con tusers y usar algunos de sus métodos, veamos como:

<!DOCTYPE html>
<html lang="eS">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>STAR CRUD</title>
</head>
<body>
 <section>
 
<?php
header("Content-Type: text/html;charset=utf-8");
include_once("tcontrol.php");
/*
Este es el controlador da la página rgister aquí deberemos incluir el modelo tusers, es decir la clase que gestiona la
tabla users. Aquí recibiremos los datos de alta un nuevo usuario y los trataremos tanto para la subida a
la BBDD, como para otras cosas.
*/  
 
//Recogemos los datos del formulario por el nombre del botón de submit  name="nuevo_usuario_btn"
//es el submit del form, y los datos vienen por post, es decir si existe la variable global es que
//se ha apretado el botón de submit
 
if(isset($_POST["nuevo_usuario_btn"]))
{
    //Recogemos los datos en variables, los cazamos por el nombre de input
    $u_name = $_POST["name_txt"];
    $u_email = $_POST["email_txt"];
    $u_password = $_POST["password_txt"];
 
    //creamos una instancia del método userRegister() de tcontrol.php
    //este metodo espera el siguiente payload:
    //public function userRegister($u_name, $u_email, $u_password, $u_img)
    $u_r = new Tcontrol();
    $new_user = $u_r->userRegister($u_name, $u_email, $u_password);
}
 
?>
 </section>
</body>
</html>

 Como puedes ver usamos la función isset() de php para saber si el botón submit de nombre nuevo_usuario_btn ha sido activado, si es así accedemos a las variables globales $_POST[“nombre_del_input”] que se ha creado de forma automática al enviar le form.

Recogemos esa información y la guardamos en variables. Por ultimo creamos una instancia del controlador Tcontrol, para poder usar su métodos userRegister() que está esperando como payload estos datos que hemos recibido.

 CREANDO EL CONTROLADOR Tcontrol.php

En la carpeta controles, vamos a crear un nuevo archivo que llamaremos Tcontrol:


Este es el controlador que se encargará de la relación entre la vistas y los modelos y donde vamos a crear el método userRegister que acabamos de crerar en gestiónvista.php, para ello lo primero es incluir en este archivo los modelos de nuestras tablas. No es necesario incluir el modelo dbaccess ya que será los modelos de cada tabla los que hablarán con ese modelo.

Como vamos aquí ya a tratar con los  datos que vienen de la vista es importante añadir una cabecera con la codificación utf-8

<?php
header("Content-Type: text/html;charset=utf-8");
 
//Clase de CONTROLADOR
include_once ("../models/tusers.php");
include_once ("../models/tplanets.php");
 
?>

 

IMPORTANTE: Es en este controlador general donde vamos a establecer las credenciales para la conexión con la base de datos. Ya que los métodos que vamos a crear aquí son instancias de los métodos de los modelos tusers y tplanets, y además de enviar a esto métodos como payload los datos recogidos en las vistas, también deberemos enviar las credenciales de conexión a la base de datos que esos métodos de los modelos requieren, veamoslo:

En el constructor definimos las credenciales de conexión a la base de datos NOTA: ES  IMPORTANTE MANTENER EL ORDER: servidor, usuario, password, base de datos.

<?php
header("Content-Type: text/html;charset=utf-8");
 
//Clase de CONTROLADOR
include_once ("../models/tusers.php");
include_once ("../models/tplanets.php");
 
class Tcontrol()
{
    private $servidor;
    private $usuario;
    private $password;
    private $base_datos;
 
    function __construct()
    {
       
        $this->servidor = "localhost";
        $this->usuario = "root";
        $this->password = "";
        $this->base_datos = "stardb";  
    }
}
?>

 Creamos ahora el método que invocamos desde gestionvista, el método se llama userRegister y recibe como payload los datos del form:

//______________________________Métodos__________________________
public function userRegister($u_name, $u_email, $u_password)
{
  /*
  Creamos una instancia dela clase Tuser que espera el siguiente payload:
 
    function __consturctor($u_name, $u_email, $u_password, $u_img, $db, $host, $user, $password)
 
  donde los que empiezan por u_ son los datos que vienen desdela vista (form) y el resto son las credenciales
  para la conexión de la base de datos.
  Es importante poner el payload en el orden que la clase Tuser los espera recibir,
  */
    $u = new Tusers($u_name, $u_email, $u_password, $this->host, $this->user, $this->password, $this->db);
   
    //Invoco el método de la clase Tuser register guardando la respuesta una variable
    $res = $u->register();
    return $res;
}

 

Como puedes ver este método crea una instancia de la clase Tusers (el modelo de la tabala users) y en el payload, envía los datos recogidos del form pero además las credenciales de conexión al método register de la clase Tusers.

Acuerdate que cuando creamos la clase Tusersrecibíamos en el constructor, todo este payload:

Constructor de la clase Tusers:

class Tusers
{
    //Propiedades privadas
    private $username;
    private $email;
    private $password;
    private $img;
 
    private $dba;
 
 
    //Constructor
    function __construct($u_name, $u_email, $u_password,  $host, $user, $password, $db)
    {
        //Adquisición de datos
        $this->username = $u_name;
        $this->email = $u_email;
        $this->password = $u_password;
 
        //Instancia de la clase DBaccess y llamada a su método connect_DB que guardamos en la propiedad dba.
        $v_dba = new DBaccess ($host, $user, $password, $db);   //-----------------------------------------No está llegando la info de credenciales FALLO 1
        //$v_dba = new DBaccess ('stardb','localhost','root','');
        $this->dba =  $v_dba;
        $this->dba->connect_DB();  //Guardo la conexiòn a la bbdd
 
   

 Por tanto Tusers, ya dispone de este payload y su método register puede acceder a el y usar métodos del modelo dbaccess para insertar el usuario en la base de datos.

Pongámoslo a prueba:

Vamos a la página register:


Ahora mismo la tabla users de la base de datos está vacía



Creemos un usuario



 El sistema nos alerta del registro





Si vamos a nuestra base de datos y refrescamos veremos que en la tabla users se ha cargado nuestro primer usuario



PONIENDO A PRUEBA NUESTRO MÉTODO user_exists()

Ahora que ya tenemos un usuario en nuestra base de datos, ¿Qué pasa si tratamos de registrarnos con el mismo mail? Lo que debe ocurrir es que nuestro método user_exists, nos alertará de que ya existe un usuario con ese mail y no cargará el nuevo usuario en la base de datos, veamos si es cierto.

Intento registrarme con el mismo mail:

El sistema nos alerta de que el mail ya está en uso


Y si vamos a nuestra base de datos podremos ver que no se ha cargado / duplicado el usuario. Por lo tanto todo está funcionando correctamente.









No hay comentarios:

Publicar un comentario