Saltar la navegación

1.7.- Ejemplo de POO en PHP.

Imagen de parte de un teclado con retroalimentación azul.
Soumil Kumar (Dominio público)

Es hora de llevar a la práctica lo que has aprendido. Vamos a aplicar los principios de la POO para realizar un "CRUD" a la tabla "productos" de la base de datos "proyecto" usada en unidades anteriores. Recuerda que las credenciales para acceder a la base de datos eran "gestor::secreto" y en la tabla usuarios habíamos creado los usuarios "admin::secreto" y "gestor::pass". En los enlaces siguientes puedes ver un vídeo en "youtube" de la aplicación ya terminada y un resumen textual del vídeo.

Básicamente si accedemos como invitado podremos ver el listado de productos y el detalle de cada uno de ellos, y si nos validamos podremos también crear, borrar y actualizar productos.

Vamos a utilizar una estructura para esta práctica muy común, en el directorio donde guardemos los archivos de la práctica crearemos una carpeta "class" donde guardaremos todas las clases y un carpeta "public" donde guardaremos todas las páginas "php, html...", que vayamos a necesitar visualizar en el navegador.

Imagen donde se puede ver una estructura de árbol de los directorios class y public, dentro de ellos los archivos correspondientes.
Captura de pantalla terminal Ubuntu (Elaboración propia)

Crearemos una clase "Conexion" y una clase para todas las tablas que vayamos a usar. El convenio es poner el nombre del archivo exactamente igual al nombre de la clase que implementa, es decir, el archivo "Usuario.php" implementará la clase "Usuario".

Para no tener que estar haciendo el "require" de cada uno de los archivos de clase que vayamos a necesitar,  vamos a utilizar la "autocarga de las clases", que es básicamente un mecanismo por el que cada vez que instanciamos un objeto de una clase hace el "require" del archivo donde se encuentra implementada. Por eso es muy importante que respete las convenciones de nombres. El código para ello sería el siguiente:

spl_autoload_register(function ($class) {
    require "../class/" . $class . ".php";
});

Utiliza una función anónima en la llamada, no te preocupes por eso ahora, el funcionamiento es, que cuando en cualquier archivo del directorio "public" hacemos una declaración del tipo "$objeto=new Objeto()" automáticamente busca un archivo en el directorio "class" (un nivel por abajo, de ahí el "..") llamado "Objeto.php" para hacer el "require", si no existe me dará un error.

Veamos el contenido de los archivos:

  • Conexion.php:Descargar conexion.php. (pdf - 28,44 KB) Implementa la clase "Conexion" que contendrá básicamente los parámetros para conectarnos, así como un método "getConexion()", que nos devolverá la conexión. Todas las demás clases heredarán de esta, todo sus atributos serán "private" menos el de la conexión que lo hacemos "protected".
  • Usuario.php:Descargar usuario.php. (pdf - 28,02 KB) Implementa la clase "Usuario" que contendrá los atributos de la tabla usuario. Tiene el método "isValido($usu, $pass)" que devolverá true si encuentra a un usuario con esa contraseña y false en otro caso.
  • Familia.php:Descargar familia.php. (pdf - 25,50 KB) Implementa la clase "Famila" que contendrá los atributos de la tabla usuario. Tiene el método "recuperarFamilias()" que usaremos para rellenar los "options" para la lista desplegable del campo familia en crear y actualizar productos, este método devuelve el "$stmt".
  • Producto.php:Descargar producto.php. (pdf - 38,89 KB) Implementa la clase "Producto" que contendrá los atributos de la tabla producto. Tiene a parte del constructor los "setter" para cada uno de los atributos, un método para cada una de las operaciones de CRUD, el método "existeNombreCorto($n)" que devolverá true si el nombre corto pasado por parámetro existe y false en otro caso y el método "recuperarProductos()" que devuelve el "$stmt" de la consulta para recuperar los productos ordenados alfabéticamente, este método me servirá para mostrar los productos en "listado.php".
    function existeNombreCorto($nc){
            if ($this->id == null) {
                $consulta = "select * from productos where nombre_corto=:nc";
            } else {
                $consulta = "select * from productos where nombre_corto = :nc AND id != :i";
            }
            $nc = func_get_arg(0);
            $stmt = $this->conexion->prepare($consulta); //podemos acceder a conexion al ser "protected"
            try {
                if ($this->id == null)
                    $stmt->execute([':nc' => $nc]);
                else
                    $stmt->execute([':nc' => $nc, ':i' => $this->id]);
            } catch (PDOException $ex) {
                die("Error al comprobar el nombre corto: " . $ex->getMessage());
            }
            if ($stmt->rowCount() == 0) return false; //No existe
            return true; //existe
    }

    Fíjate que en este método tenemos que controlar si estemos en crear (compruebo que no existe ese nombre_corto en toda la base de datos) o actualizar (no comprobaremos el nombre_corto del código del producto a actualizar ya que ese nombre_corto ya existe).

Para todas las clases que heredan de la clase Conexión el constructor será:

public function __construct(){
        parent::__construct();
}

Recomendación

Podemos instalar en Visual Studio Code, multitud de extensiones que nos ayudarán en nuestro desarrollo, una de ellas es "PHP Getters & Setters" que nos crea automáticamente los "getters" y los "setters" del atributo que deseemos. Una vez instalada sólo tenemos que hacer click derecho sobre el atributo que queramos y nos aparecerá en el menú contextual la opción de crear el "get", el "set" o ambos.