Patrón CRUD en PHP

Categories:

Antes de comenzar, hago mención que el propósito de esta entrada es contar con una referencia de cómo organizo los archivos en PHP para poder realizar las operaciones básicas de los registros – Crear, Leer, Actualizar, Eliminar -. El código escrito es vulnerable a inyección SQL. Esa vulnerabilidad se puede mitigar con sentencias preparadas.

Preferí presentar esta parte de manera independiente aún con las vulnerabilidades en el código para poder tratar cada tema de manera independiente y evitar – en la medida de lo posible – las confusiones que se pudieran generar.

Por favor no utilices este código ni siquiera como referencia para sus aplicaciones porque la vulnerabilidad está presente.

En MySQL vimos las tareas generales de los registros – crear, leer, actualizar, eliminar -. También vimos los formularios y cómo conectarnos con PHP a MySQL. Con esos tres conceptos vamos a implementar las tareas generales – conocidas como el patrón CRUD – en PHP.

En la sección “Aplicaciones web” de la organización de proyectos se muestra una carpeta llamada “tablas”.

Dentro de esa carpeta vamos a crear siete archivos – el nombre de los archivos y la manera de organizar el código lo tomé “prestado” del scaffold de Ruby on Rails aunque lo que vamos a hacer está muy alejado del framework – que van a cumplir funciones particulares.

Archivo Descripción

index.php

Archivo inicial para la administración de una tabla.
Este es el único archivo de la carpeta en el cual se va a visualizar una “colección” de datos,
es decir, se pueden visualizar prácticamente todos los registros en esta página – a menos que no haya registros, que solo haya uno o que se utilice un paginador -.

show.php

Este archivo recibe un identificador – id – con el cual obtiene un registro de una tabla.
Los datos obtenidos se van a visualizar en este archivo.

new.php

Este archivo contiene un formulario el cual tiene asociados los datos de la tabla que representa.

create.php

Este archivos recibe los valores del formulario que está en el archivo new.php
Con los datos recibidos va a crear un registro en la base de datos y se redirige al archivo inicial – index.php -.

edit.php

Este archivo recibe un identificador – id – con el cual va a obtener el registro de una tabla.
Con el registro se va a llenar un formulario para que, al enviarlo se actualicen los datos.

update.php

Este archivo recibe valores de un formulario.
Va a utilizar el identificador – id – para seleccionar un registro de una tabla y,
los demás valores van a sobrescribir el contenido que estaba almacenado.

destroy.php

Este archivo recibe un identificador – id – que va a utilizar para eliminar un registro de una tabla.

Los archivos quedarían de la siguiente manera:

Si asociamos los archivos en PHP con la sentencia SQL correspondiente y los clasificamos con base en cada una de las tareas del patrón CRUD nos quedaría algo parecido a lo siguiente:

Navegación entre archivos
Antes de entrar de lleno al código creo que es conveniente visualizar cómo están relacionados los archivos.

Para el ejemplo vamos a utilizar la tabla “niveles” de la base de datos “tutoriales” que se ha utilizado en otras publicaciones – sobre todo de MySQL -.

Elegí esta tabla porque, aunque tiene definidas cuatro columnas, sólo vamos a utilizar la columna nombre directamente.

index.php

<?php 
  require 'config.php'; 
  $query = "SELECT * FROM niveles";
  $results = $conexion->query($query);  
  /*
  * Obtener todos los registros que 
  * se encuentran en la tabla niveles
  */
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
  </head>
  <body>
    
    <h1>Niveles</h1>
    <table>
      <thead>
        <tr>
          <th>id</th>
          <th>Nombre</th>
          <th>Creado</th>
          <th>Actualizado</th>
          <th> </th>
          <th> </th>
          <th> </th>                    
        </tr>
      </thead>
      <tbody>
          <?php
          while ($result = $results->fetch_array()) {
            ?>
          <tr>
            <td><?php echo $result['id']; ?></td>
            <td><?php echo $result['nombre']; ?></td>
            <td><?php echo $result['creado']; ?></td>
            <td><?php echo $result['actualizado']; ?></td>
            <td>
                <!-- Enlace hacia el archivo show.php -->
                <a href="show.php?id=<?php echo $result['id']; ?>">Ver</a>
            </td>
            <td>
                <!-- Enlace hacia el archivo edit.php -->
                <a href="edit.php?id=<?php echo $result['id']; ?>">Editar</a>
            </td>
            <td>
                <!-- 
                    Acción hacia destroy.php
                    En este caso se utiliza un formulario porque el método de envío de datos tiene que ser POST.
                    Al presionar un enlace - link - se genera una petición hacia el servidor que utiliza el método GET.
                 -->
                <form action="destroy.php" method="post">
                  <input type="hidden" name="id" value="<?php echo $result['id']; ?>">
                  <input type="submit" name="eliminar" value="Eliminar">
                </form>
            </td>
          </tr>
            <?php
          }          
          ?>
      </tbody>
    </table>
    
    <p>
      <!-- Enlace hacia el archivo new.php -->
      <a href="new.php">Agregar Nivel</a>
    </p>
    
  </body>
</html>

show.php

<?php 
  require 'config.php'; 
  $query = "SELECT * FROM niveles WHERE id = '" . $_GET['id'] . "'";  
  $results = $conexion->query($query);  
  $result = $results->fetch_array();
  /**
  * Obtener el registro del cual se quieren visualizar los datos.
  **/
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
  </head>
  <body>
      
    <h1>Nivel</h1>
    <table>
      <thead>
        <tr>
          <th>id</th>
          <th>nombre</th>
          <th>creado</th>
          <th>actualizado</th>
        </tr>
      </thead>
      <tbody>
          <tr>
            <td><?php echo $result['id']; ?></td>
            <td><?php echo $result['nombre']; ?></td>
            <td><?php echo $result['creado']; ?></td>
            <td><?php echo $result['actualizado']; ?></td>
          </tr>
      </tbody>
    </table>
    
    <p>
      <!-- Enlace para regresar a la página principal -->
      <a href="index.php">Regresar</a>
    </p>
    
    
  </body>
</html>

new.php

<?php require 'config.php'; ?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
  </head>
  <body>
    <h1>Crear Nivel</h1>
    
    <!-- Acción hacia el archivo create.php -->
    <form action="create.php" method="post">
      <label>Nombre</label><br>
      <input type="text" name="nombre" ><br>
      <input type="submit" name="crear" value="Crear">
    </form>
    
  </body>
</html>

create.php

<?php
  require 'config.php';
  $nombre = $_POST['nombre'];    
  /* 
    Para llenar las columnas 'creado' / 'actualizado' utilizamos la función NOW() de MySQL
  */
  $query = "INSERT INTO niveles(nombre, creado, actualizado) VALUES ('" . $nombre . "', NOW(), NOW())";
  $conexion->query($query)
  header('Location: index.php');
?>

edit.php

<?php 
  require 'config.php'; 

  $query = "SELECT * FROM niveles WHERE id = '" . $_GET['id'] . "'";
  $results = $conexion->query($query);  
  $result = $results->fetch_array();
  /**
  *  Obtener el registro a editar 
  */
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
  </head>
  <body>
    
    <h1>Editar Nivel</h1>    
    <!-- Acción hacia el archivo update.php -->    
    <form action="update.php" method="post">
      <input type="hidden" name="id" value="<?php echo $result['id']; ?>" >
      <label>Nombre</label><br>      
      <input type="text" name="nombre" value="<?php echo $result['nombre']; ?>" ><br>
      <input type="submit" name="crear" value="Actualizar">
    </form>
    
  </body>
</html>

update.php

<?php
  require 'config.php';
  $id = $_POST['id'];
  $nombre = $_POST['nombre'];
  /*
    El valor de id se va a utilizar para seleccionar el registro a modificar. 
    El único atributo que va a ser actualizado por el usuario es valor de la columna nombre
    En este caso únicamente se modifica la columna 'actualizado' para poder comparar la fecha de creación con la fecha de actualización.
  */
  $query = "UPDATE niveles SET nombre = '" . $nombre . "', actualizado = NOW() WHERE id = '" . $id . "'";
  header('location: index.php');    
?>

destroy.php

<?php
  require 'config.php';    
  $id = $_POST['id'];
  /*
    Se utiliza el atributo id para seleccionar el registro a elimina.
  */
  $query = "DELETE FROM niveles WHERE id = '" . $id . "'";
  $conexion->query($query);
  header('Location: index.php');
?>

Adjunto la carpeta ‘niveles’ con los archivos mencionados en esta entrada.

Esta carpeta incluye el archivo config.php en el cual se asignan las credenciales para conectarse a la base de datos – y así no tener que levantar todo el proyecto -.