Inicio » Blog » PHP

MVC en PHP y MySql Básico

Modelo vista controlador con conexiones PDO en PHP, sencilla aplicación web desarrollada con un CRUD para la gestión de consultas Mysql, Descarga el código

DESARROLLO DE UN SISTEMA MVC EN PHP Y MYSQL 

Desarrollaremos un sistema modelo vista controlador básico, justo para entender ¿Cómo funciona este patrón de diseño de arquitectura de Software?.

Aquí tienes un link del demo de la aplicación MVC en PHP + MYSQL básico

 

Desarrolla un Sistema MVC Básico en PHP y MySQL (Actualizado 2026)

Desarrolla un Sistema MVC Básico en PHP y MySQL (Actualizado 2026)

Desarrolla un Sistema MVC Básico en PHP y MySQL (Actualizado 2026)

Bienvenido a esta guía paso a paso para crear un sistema MVC en PHP y MySQL! Si eres principiante en desarrollo web, este tutorial te enseña a implementar el patrón MVC (Model-View-Controller) de manera sencilla y efectiva. Construiremos un CRUD básico para gestionar productos, ideal para entender la separación de responsabilidades en la arquitectura de software.

¿Qué es el Patrón MVC?

El MVC es un patrón arquitectónico de software que divide la aplicación en tres capas interconectadas para promover código mantenible, escalable y colaborativo. En desarrollo web con PHP, es fundamental para proyectos medianos a grandes.

Componentes Clave:

Componente Descripción Rol en PHP/MySQL
Modelo (Model) Maneja datos y lógica de negocio. Conexión a MySQL, consultas CRUD.
Vista (View) Presenta la interfaz al usuario. HTML/CSS para renderizar datos.
Controlador (Controller) Procesa entradas y coordina flujo. Enruta peticiones HTTP, actualiza modelo y selecciona vista.

Este ejemplo de MVC en PHP usa un enfoque vanilla (sin frameworks) para que entiendas los fundamentos.

Desarrolla un Sistema MVC Básico en PHP y MySQL (Actualizado 2026)

Objetivos del Proyecto y Requisitos Previos

Objetivos del Proyecto y Requisitos Previos

Objetivos del Proyecto y Requisitos Previos

Objetivos del Proyecto

Crearemos un sistema de gestión de productos con:

  • Backend: PHP 8+ y MySQL.
  • Frontend: HTML, CSS básico.
  • Patrón: MVC puro para un CRUD en una tabla simple.

Duración estimada: 1-2 horas. Resultado: App funcional en localhost.

Requisitos Previos

Asegúrate de tener instalado lo siguiente para tu entorno de desarrollo PHP MVC:

Requisito Detalle Enlace de Descarga
Servidor Local XAMPP (Apache, MySQL, PHP 8.2+) apachefriends.org
Editor de Código VS Code (con extensiones PHP Intelephense) code.visualstudio.com
Navegador Chrome/Firefox para depuración N/A
Conocimientos Básicos PHP, SQL, HTML/CSS N/A

Inicia XAMPP y verifica http://localhost (Apache) y http://localhost/phpmyadmin (MySQL).


Funcionalidades del CRUD

Funcionalidades del CRUD

Funcionalidades del CRUD

Implementaremos operaciones esenciales en nuestro CRUD MVC PHP:

  • Leer (Read): Listar todos los productos.
  • Crear (Create): Agregar nuevo producto (nombre y precio).
  • Actualizar (Update): Editar producto existente.
  • Eliminar (Delete): Borrar producto con confirmación.

Flujo: Usuario → Vista → Controlador → Modelo → MySQL → Respuesta.


Diseño de la Base de Datos

Diseño de la Base de Datos

Diseño de la Base de Datos

Usa MySQL para el modelo de datos en MVC. Diseñamos una BD simple y normalizada.

Pasos de Implementación:

  1. Accede a phpMyAdmin (http://localhost/phpmyadmin).
  2. Crea BD: mvc (collation: utf8mb4_unicode_ci para soporte internacional).
  3. Crea tabla: productos con campos optimizados para e-commerce básico.

Esquema de Tabla:

Campo Tipo Atributos Descripción
id INT(11) PRIMARY KEY, AUTO_INCREMENT Identificador único.
nombre VARCHAR(50) NOT NULL Nombre del producto.
precio DECIMAL(7,2) NOT NULL Precio en soles (ej: 123.45).

Script SQL de Creación

Copia y ejecuta este script en phpMyAdmin para generar la estructura:

SQL

CREATE DATABASE IF NOT EXISTS `mvc` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `mvc`;

CREATE TABLE `productos` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `nombre` VARCHAR(50) NOT NULL,
  `precio` DECIMAL(7,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Verificación: Inserta datos de prueba manualmente: INSERT INTO productos (nombre, precio) VALUES ('Teclado USB', 25.99);.


Estructura de Archivos

Estructura de Archivos

Estructura de Archivos

Organiza el proyecto en htdocs/mvc/ para reflejar el MVC en carpetas PHP. Esto promueve modularidad.

mvc/
├── index.php          # Enrutador principal
├── config.php         # Configuraciones globales
├── controlador/       # Lógica de control
│   └── index.php
├── modelo/            # Acceso a datos
│   └── index.php
└── vista/             # Interfaz de usuario
    ├── css/
    │   └── app.css
    ├── layout/
    │   ├── header.php
    │   └── footer.php
    ├── index.php      # Lista principal
    ├── nuevo.php      # Formulario crear
    └── editar.php     # Formulario editar

 

Crea las carpetas con tu editor. Nota: Eliminar no necesita vista separada (se maneja por POST/redirect).

 


Configuración Inicial y Conexión a BD

Configuración Inicial y Conexión a BD

Configuración Inicial y Conexión a BD

Define constantes y enruta peticiones. Ajusta URLSITE a tu puerto XAMPP (ej: 80 o 8888).

config.php:

PHP

define('URLSITE', 'http://localhost/mvc/');  // Ajusta según tu setup

index.php (Enrutador):

PHP

// 1. CARGAR LA CONFIGURACIÓN GLOBAL
require_once("config.php");

// 2. CARGAR EL CONTROLADOR BASE
require_once("controlador/index.php");

// 3. CREAR INSTANCIA DEL CONTROLADOR
$controller = new ProductoController();

// 4. DETERMINAR QUÉ MÉTODO EJECUTAR
// Por defecto carga el método 'index' si no se especifica otro
$metodo = $_GET['m'] ?? 'index';

// 5. VERIFICAR Y EJECUTAR EL MÉTODO SOLICITADO
if(method_exists($controller, $metodo)) {
    // Ejecuta el método de forma segura
    $controller->$metodo();
} else {
    // Manejo de error 404 si el método no existe   
}

Mejora: Agregado fallback para rutas inválidas.


Creando el Modelo en PHP para el Patrón MVC

Vamos a desglosar la clase Modelo que forma parte de la arquitectura MVC, encargada de gestionar todos los accesos a la base de datos.

Estructura básica y conexión a la base de datos

php

require_once("config.php");

class Modelo {
    private $datos = [];
    private $db;

La clase contiene dos propiedades privadas:

  • $datos: Un array para almacenar información (aunque no se usa en este ejemplo)
  • $db: El manejador de conexión a la base de datos

El constructor establece la conexión usando PDO:

php

public function __construct() {
    try {
        $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4";
        $this->db = new PDO($dsn, DB_USER, DB_PASS);
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch(PDOException $e) {
        die("Error de conexión: " . $e->getMessage());
    }
}

Explicación:

  • Utiliza constantes definidas en config.php para los parámetros de conexión
  • Crea un DSN (Data Source Name) para MySQL con codificación UTF-8
  • Activa el modo de excepciones para un manejo de errores más robusto
  • Finaliza la ejecución si la conexión falla

Método para insertar registros

php

public function insertar($tabla, $data) {
    $consulta = "INSERT INTO " . $tabla . " (nombre, precio) VALUES (?, ?)";
    $stmt = $this->db->prepare($consulta);
    return $stmt->execute([$data['nombre'], $data['precio']]);
}

Funcionalidad:

  • Recibe el nombre de la tabla y un array con datos
  • Prepara una consulta SQL con placeholders ? para evitar inyección SQL
  • Ejecuta la inserción con los valores del array
  • Retorna true o false según el resultado

Método para consultar registros

php

public function mostrar($tabla, $condicion = "1") {
    $consulta = "SELECT * FROM " . $tabla . " WHERE " . $condicion;
    $stmt = $this->db->query($consulta);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

Funcionalidad:

  • Recibe la tabla y una condición (por defecto "1" para obtener todos los registros)
  • Ejecuta la consulta directamente con query()
  • Retorna todos los resultados como array asociativo

Método para actualizar registros

php

public function actualizar($tabla, $data, $condicion) {
    $consulta = "UPDATE " . $tabla . " SET nombre = ?, precio = ? WHERE " . $condicion;
    $stmt = $this->db->prepare($consulta);
    return $stmt->execute([$data['nombre'], $data['precio']]);
}

Funcionalidad:

  • Similar a insertar, pero usa una consulta UPDATE
  • La condición (ej: "id = 5") se concatena directamente sin parámetros
  • Retorna el resultado de la ejecución

Método para eliminar registros

php

public function eliminar($tabla, $condicion) {
    $consulta = "DELETE FROM " . $tabla . " WHERE " . $condicion;
    $res = $this->db->exec($consulta);
    return $res > 0;
}

Funcionalidad:

  • Ejecuta un DELETE con la condición proporcionada
  • Usa exec() en lugar de execute()
  • Retorna true si se eliminó al menos un registro

Consideraciones importantes

Seguridad:

  • Los métodos insertar() y actualizar() usan prepared statements correctamente
  • Crítico: mostrar() y eliminar() concatenan directamente la condición, vulnerable a inyección SQL si no se sanitiza previamente

Limitaciones:

  • Los campos nombre y precio están hardcodeados, no son dinámicos
  • Solo funciona para tablas con esos campos específicos
  • No hay validación de los datos recibidos

Ejemplo de uso básico

php

// Crear instancia del modelo
$modelo = new Modelo();

// Insertar un producto
$modelo->insertar("productos", ["nombre" => "Laptop", "precio" => 899.99]);

// Mostrar todos los productos
$productos = $modelo->mostrar("productos");

// Actualizar un producto
$modelo->actualizar("productos", ["nombre" => "Laptop Pro", "precio" => 999.99"], "id = 1");

// Eliminar un producto
$modelo->eliminar("productos", "id = 5");

Este modelo proporciona operaciones CRUD básicas que serían llamadas por el Controlador en la arquitectura MVC.


Creando el Controlador en PHP para el Patrón MVC

Vamos a analizar el ProductoController, encargado de gestionar la lógica de negocio y coordinar el modelo con las vistas.

Estructura básica e inicialización

php

require_once("modelo/index.php");

class ProductoController {
    private $modelo;
    
    function __construct() {
        $this->modelo = new Modelo();
    }

El controlador instancia el modelo en su constructor, estableciendo la conexión a la base de datos que usarán todos los métodos.

Método index - Listar productos

php

function index() {
    $datos = $this->modelo->mostrar("productos", "1");
    require_once("vista/index.php");
}

Funcionalidad:

  • Obtiene todos los productos llamando al modelo
  • Carga la vista principal pasándole los datos automáticamente
  • Es el método por defecto cuando no se especifica acción

Método nuevo - Formulario de creación

php

function nuevo() {
    require_once("vista/nuevo.php");
}

Funcionalidad:

  • Simplemente carga el formulario para crear un nuevo producto
  • No interactúa con el modelo, solo muestra la vista

Método guardar - Crear producto

php

function guardar() {
    if(isset($_GET['nombre']) && isset($_GET['precio'])) {
        $data = [
            'nombre' => trim($_GET['nombre']),
            'precio' => floatval($_GET['precio'])
        ];
        $this->modelo->insertar("productos", $data);
    }
    header("Location: " . URL_SITE);
    exit();
}

Funcionalidad:

  • Recoge datos del **G​ET∗∗(deberıˊaser _POST)
  • Sanitiza el nombre con trim() y el precio con floatval()
  • Inserta mediante el modelo y redirige a la página principal

Método editar - Formulario de edición

php

function editar() {
    $id = intval($_GET['id'] ?? 0);
    $dato = $this->modelo->mostrar("productos", "id = " . $id);
    require_once("vista/editar.php");
}

Funcionalidad:

  • Obtiene el ID del producto a editar
  • Busca el registro específico en la base de datos
  • Carga la vista de edición con los datos del producto

Método update - Actualizar producto

php

function update() {
    if(isset($_GET['id'], $_GET['nombre'], $_GET['precio'])) {
        $id = intval($_GET['id']);
        $data = [
            'nombre' => trim($_GET['nombre']),
            'precio' => floatval($_GET['precio'])
        ];
        $this->modelo->actualizar("productos", $data, "id = " . $id);
    }
    header("Location: " . URL_SITE);
    exit();
}

Funcionalidad:

  • Similar a guardar, pero para actualizar registros existentes
  • Usa la condición id = X para identificar el producto

Método eliminar - Borrar producto

php

function eliminar() {
    $id = intval($_GET['id'] ?? 0);
    $this->modelo->eliminar("productos", "id = " . $id);
    header("Location: " . URL_SITE);
    exit();
}

Funcionalidad:

  • Recibe el ID del producto a eliminar
  • Ejecuta la eliminación mediante el modelo
  • Redirige inmediatamente a la página principal

Router simple

php

$controller = new ProductoController();
$metodo = $_GET['m'] ?? 'index';

if(method_exists($controller, $metodo)) {
    $controller->$metodo();
} else {
    http_response_code(404);
    echo "Página no encontrada";
}

Funcionalidad:

  • Crea la instancia del controlador
  • Lee el parámetro m de la URL (por ejemplo: ?m=editar&id=5)
  • Verifica que el método exista y lo ejecuta
  • Muestra error 404 si el método no existe

Ejemplos de URLs

php

// Listar productos:
index.php

// Formulario nuevo:
index.php?m=nuevo

// Guardar producto (URL insegura):
index.php?m=guardar&nombre=Producto&precio=100

// Editar producto con ID 3:
index.php?m=editar&id=3

// Actualizar producto (URL insegura):
index.php?m=update&id=3&nombre=Nuevo&precio=150

// Eliminar producto con ID 5 (¡muy inseguro!):
index.php?m=eliminar&id=5

Este controlador implementa el patrón MVC básico pero requiere mejoras de seguridad para uso en producción.


Sistema de Layouts y Vista Index

el sistema de plantillas que estructura la interfaz de usuario, compuesto por un layout base (header/footer) y vistas específicas.

Layout Principal: header.php

php

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Sistema MVC en PHP y MySQL - Gestión de productos">
    <title>Gestión de Productos - MVC PHP</title>
    <link rel="stylesheet" href="<?= URL_SITE ?>vista/css/app.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>🛒 SISTEMA DE GESTIÓN DE PRODUCTOS</h1>
            <h2>MVC EN PHP + MYSQL V.01</h2>
        </header>
        <main>

Funcionalidad:

  • Define la estructura HTML5 básica con metadatos SEO
  • Usa URL_SITE para rutas dinámicas al CSS
  • Crea un contenedor principal con <div class="container">
  • Incluye el header de la aplicación y abre la etiqueta <main>
  • Importante: No cierra <main>, esto se hace en footer.php

Layout Principal: footer.php

php

        </main>
        <footer>
            <p>&copy; <?= date('Y') ?> Tutorial MVC PHP - Todos los derechos reservados</p>
        </footer>
    </div>
</body>
</html>

Funcionalidad:

  • Cierra la etiqueta <main> que se abrió en header.php
  • Añade el pie de página con copyright dinámico
  • Cierra todas las etiquetas abiertas en header.php (</div>, </body>, </html>)
  • Garantiza que el HTML quede bien formado

Sistema de Inclusión en Vistas

Cada vista sigue este patrón:

php

<?php
require_once("layouts/header.php");
?>
<!-- CONTENIDO ESPECÍFICO DE LA VISTA -->
<?php
require_once("layouts/footer.php");
?>

Ventajas:

  • Reutilización: El header y footer se definen una sola vez
  • Mantenibilidad: Cambios en el layout afectan a todas las vistas
  • Consistencia: Todas las páginas tienen la misma estructura base

Ejemplo: Formulario de Edición

Analicemos el formulario de edición:

php

<form action="<?= URL_SITE ?>" method="get" class="edit-form">
    <?php 
    $producto = $dato[0] ?? [];
    ?>
    
    <input type="hidden" name="id" value="<?= $producto['id'] ?? '' ?>">
    <input type="hidden" name="m" value="update">
    
    <div class="form-group">
        <label for="nombre">Nombre del Producto:</label>
        <input type="text" id="nombre" name="nombre" 
               value="<?= htmlspecialchars($producto['nombre'] ?? '') ?>" required>
    </div>
    
    <div class="form-group">
        <label for="precio">Precio S/:</label>
        <input type="number" id="precio" name="precio" step="0.01" 
               value="<?= htmlspecialchars($producto['precio'] ?? '') ?>" required>
    </div>
    
    <button type="submit">💾 Actualizar Producto</button>
    <a href="<?= URL_SITE ?>">❌ Cancelar</a>
</form>

Elementos clave:

Prevención de XSS:

php

value="<?= htmlspecialchars($producto['nombre'] ?? '') ?>"
  • htmlspecialchars() escapa caracteres especiales para evitar ataques XSS
  • El operador ?? (null coalescing) evita errores si el dato no existe

Enrutamiento del formulario:

  • method="get" envía datos por URL (ej: ?m=update&id=3&nombre=...)
  • Problema crítico: Las ediciones aparecen en el historial del navegador y no son seguras
  • Correcto: Debería ser method="post"

Campos ocultos:

php

<input type="hidden" name="m" value="update">
<input type="hidden" name="id" value="<?= $producto['id'] ?? '' ?>">
  • m=update indica al router que ejecute el método update() del controlador
  • id identifica qué registro se está editando

Flujo de Datos en la Vista

  1. Controlador carga la vista: require_once("vista/editar.php");
  2. Vista incluye el header: require_once("layouts/header.php");
  3. Contenido se renderiza con los datos del array $dato
  4. Vista incluye el footer: require_once("layouts/footer.php");
  5. Resultado: HTML completo enviado al navegador

Problemáticas de Seguridad

Críticos:

  • method="get" expone datos sensibles en la URL
  • Los formularios de eliminación son accesibles por URL (CSRF)
  • No hay validación de datos en el lado del cliente

Mejoras recomendadas:

php

<!-- Cambiar GET por POST -->
<form action="<?= URL_SITE ?>" method="post" class="edit-form">
    
    <!-- Añadir token CSRF -->
    <input type="hidden" name="csrf_token" value="<?= generarToken() ?>">
</form>

Estructura de Carpetas

 

/proyecto
├── /modelo
│   └── index.php
├── /controlador
│   └── index.php
├── /vista
│   ├── /css
│   │   └── app.css
│   ├── /layouts
│   │   ├── header.php
│   │   └── footer.php
│   ├── index.php
│   ├── nuevo.php
│   ├── editar.php
│   └── ...
└── config.php

 

El sistema de layouts separa correctamente la presentación de la lógica, permitiendo:

  • ✅ Estructura HTML consistente
  • ✅ Reutilización de código
  • ✅ Mantenimiento centralizado

Vista "Nuevo Producto" en MVC

Vista "Nuevo Producto" en MVC

Vista "Nuevo Producto" en MVC

Analicemos la vista encargada de mostrar el formulario de creación de productos, desglosando cada elemento y su función específica.

Estructura Base de la Vista

php

<?php require_once("layouts/header.php"); ?>
<!-- Contenido específico -->
<?php require_once("layouts/footer.php"); ?>

Este patrón encapsula el formulario dentro del layout global del sitio. El header.php abre todas las etiquetas HTML hasta <main>, y el footer.php las cierra, garantizando un documento bien formado.

Contenedor del Formulario

php

<section class="form-section">
    <h2 class="text-center">➕ Nuevo Producto</h2>
  • <section class="form-section">: Agrupa semánticamente el formulario y permite aplicar estilos específicos
  • <h2 class="text-center">: Título visual con clase para alineación centralizada mediante CSS
  • El emoji proporciona feedback visual inmediato sobre la acción

Formulario de Creación

Configuración del Formulario

php

<form action="<?= URL_SITE ?>" method="GET" class="create-form">

Atributos clave:

  • action="<?= URL_SITE ?>": Envía datos a la raíz del sitio (ej: index.php)
  • method="GET": PROBLEMA CRÍTICO - expone datos en la URL
  • class="create-form": Permite estilos específicos para formularios de creación

Campo: Nombre del Producto

php

<div class="form-group">
    <label for="nombre">Nombre del Producto:</label>
    <input type="text" id="nombre" name="nombre" required autofocus>
</div>

Análisis del input:

  • type="text": Acepta cualquier texto plano
  • id="nombre" y name="nombre": Identificadores para CSS y procesamiento
  • required: Validación del navegador que impueba envío vacío
  • autofocus: Coloca automáticamente el cursor aquí al cargar la página
  • Falta: maxlength para limitar caracteres y prevenir sobrecarga

Campo: Precio

php

<div class="form-group">
    <label for="precio">Precio (S/):</label>
    <input type="number" id="precio" name="precio" step="0.01" required>
</div>

Atributos especiales:

  • type="number": Teclado numérico en móviles, validación básica
  • step="0.01": Permite decimales (ej: 9.99)
  • required: Obligatorio
  • Falta: min="0" para evitar precios negativos

Campo Oculto de Enrutamiento

php

<input type="hidden" name="m" value="guardar">

Función esencial: Este campo es el sistema de enrutamiento de la aplicación. Al enviar el formulario, crea una URL como:

index.php?m=guardar&nombre=Producto&precio=99.99

El parámetro m=guardar indica al router que debe ejecutar la acción de guardado.

Botones de Acción

php

<div class="form-buttons">
    <button type="submit" class="btn">💾 Guardar Producto</button>
    <a href="<?= URL_SITE ?>" class="btn">❌ Cancelar</a>
</div>

Características:

  • type="submit": Botón primario que envía el formulario
  • <a href="<?= URL_SITE ?>": Enlace estilizado como botón para cancelar
  • Ambos usan class="btn" para estilos uniformes
  • Emojis (💾, ) como íconos intuitivos

Flujo de Renderizado

  • PHP procesa <?php require_once("layouts/header.php"); ?>
  • Se genera el HTML del formulario con valores dinámicos
  • PHP procesa <?php require_once("layouts/footer.php"); ?>
  • Resultado final: Documento HTML completo enviado al navegador
Vista "Nuevo Producto" en MVC

Vista "Editar Producto" en MVC

Vista "Editar Producto" en MVC

Vista "Editar Producto" en MVC

Analicemos exclusivamente el formulario de edición, desglosando cada elemento y sus implicaciones.

Extracción de Datos del Producto

php

<?php 
// Tomar el primer producto del array
$producto = $dato[0] ?? [];
?>

Función: El controlador pasa el array $dato con los resultados de la consulta. Esta línea extrae el primer (y único) registro del array. El operador ?? evita errores si $dato está vacío.

Estructura del Formulario

HTML

<form action="<?= URL_SITE ?>" method="get" class="edit-form">

Configuración:

  • action="<?= URL_SITE ?>": Envía datos a la raíz del sitio

  • PROBLEMA CRÍTICO: method="get" expone datos sensibles en la URL

  • class="edit-form": Clase CSS específica para estilos de edición

Pre-fill de Datos en los Campos

Campo nombre:

php

value="<?= htmlspecialchars($producto['nombre'] ?? '') ?>"

Características:

  • htmlspecialchars() escapa caracteres especiales (previene XSS)

  • ?? '' muestra vacío si no existe el dato

  • required fuerza completado del campo

Campo precio:

php

value="<?= htmlspecialchars($producto['precio'] ?? '') ?>"

Limitaciones:

  • Falta min="0" para evitar precios negativos

  • No hay max para limitar valores excesivos

Campos Ocultos (Enrutamiento)

php

<input type="hidden" name="id" value="<?= $producto['id'] ?? '' ?>">
<input type="hidden" name="m" value="update">

Función esencial:

  • id: Identifica qué registro actualizar
  • m=update: Indica al router que ejecute ProductoController::update()
  • Genera URL: index.php?m=update&id=5&nombre=Producto&precio=99.99

Botones de Acción

HTML

<button type="submit" class="btn">💾 Actualizar Producto</button>
<a href="<?= URL_SITE ?>" class="btn">❌ Cancelar</a>

Diseño:

  • Botón de submit con emoji como ícono visual
  • Enlace estilizado como botón para cancelar
  • Ambos usan class="btn" para apariencia consistente
Vista "Editar Producto" en MVC

Diseño UI con CSS para el Sistema MVC

Diseño UI con CSS para el Sistema MVC

Diseño UI con CSS para el Sistema MVC

el CSS que estructura la interfaz visual del sistema de gestión de productos.

Variables de Diseño (Custom Properties)

css

 

:root {
  --background-color: #650a4e;
  --btn-color: #667eea;
}

Función: Define colores reutilizables en todo el proyecto. Cambiar aquí afecta a header, footer y botones automáticamente.

Reset y Estilos Base

css

 

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
}
  • box-sizing: border-box: Incluye padding y border en el tamaño total (evita desbordamientos)

  • linear-gradient: Fondo degradado de lavanda a morado que ocupa toda la pantalla

  • min-height: 100vh: Garantiza que el fondo cubra incluso con poco contenido

Contenedor Principal

css

 

.container {
    max-width: 1200px;
    margin: 0 auto;
    background: white;
    min-height: 100vh;
    box-shadow: 0 0 20px var(--background-color)
}

Efecto visual: Crea una "página" central blanca con sombra morada, anclada al viewport. El margin: 0 auto centra horizontalmente.

Secciones de Contenido

css

 

.section{
    max-width: 800px;
    margin: 50px auto;
    border-radius: 10px;
    box-shadow: 0px 0px 15px 0px rgba(42, 31, 198, 0.508);
}

Uso: Para envolver listados o formularios (asignar esta clase al <section>). Genera tarjeta centrada con sombra suave.

Cabecera (Header)

css

 

header {
    background: var(--background-color);
    color: white;
    padding: 2rem;
    text-align: center;
}

header h1 {    
    font-size: 2rem;
}

Diseño: Fondo morado oscuro con texto blanco centrado. Padding generoso (2rem) para impacto visual.

Tipografía

css

 

h2{    
    padding-bottom: 20px;
}

.text-center{
    text-align: center;
}
.text-end{
    text-align: right;
}

Aplicaciones:

  • h2: Títulos de secciones con espacio inferior

  • text-center: Títulos de formularios

  • text-end: Potencial uso en columnas de acciones de tabla

Botones

css

 

.btn {
    color: white;
    text-decoration: none;
    padding: 0.5rem 1.5rem;
    border-radius: 5px;
    transition: all 0.3s;
    font-weight: bold;
    background: var(--btn-color);
    display: inline-block;
}

.btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}

Interacción:

  • Normal: Botón azul con texto blanco

  • Hover: Sube 2px y gana sombra, creando efecto "elevación" suave

  • transition: all 0.3s: Animación fluida en ambos estados

Tablas (Listado de Productos)

css

 

.table-responsive {
    overflow-x: auto;
    margin: 0.5rem 0;
    padding: 16px;
}

.table {
    width: 100%;
    border-collapse: collapse;
}

.table th, .table td {
    padding: 1rem;
    text-align: left;
    border-bottom: 1px solid #ddd;
}

.table th {
    background: var(--background-color);
    color: white;
}

.table tr:hover {
    background: #f5f5f5;
}

Características:

  • .table-responsive: Scroll horizontal en móviles si la tabla es ancha

  • border-collapse: collapse: Bordes unificados entre celdas

  • Hover en fila: Feedback visual al pasar el mouse

  • Header morado oscuro, celdas con borde gris claro

Formularios

css

 

form {
    max-width: 500px;
    margin: 2rem auto;
    padding: 2rem;
    background: #f8f9fa;
    border-radius: 10px;
}

input[type="text"], input[type="number"] {
    width: 100%;
    padding: 0.8rem;
    margin: 0.5rem 0 1rem;
    border: 1px solid #ddd;
    border-radius: 5px;
}

Diseño: Tarjeta gris clara centrada con inputs de ancho completo y bordes redondeados. El margin: 0.5rem 0 1rem crea espacio superior pequeño e inferior grande.

Pie de Página (Footer)

css

 

footer {
    text-align: center;
    padding: 2rem;
    background: var(--background-color);
    color: white;
    margin-top: 3rem;
}

Posicionamiento: margin-top: 3rem empuja el footer hacia abajo, separándolo del contenido.

Diseño UI con CSS para el Sistema MVC


Leido 76007 veces | 167 usuarios

Descarga del código fuente

MVC en PHP y MySql Básico

Accede al código fuente esencial de nuestra aplicación en formato ZIP ó TXT. Ideal para desarrolladores que desean personalizar o integrar nuestra solución.

  • [ Pago: Paypal ]
  • [ Precio: USD 5.00 ]
  • [ Descargas: 2615 ]

Compartir link del tutorial con tus amigos

Preguntas de MVC en PHP y MySql

1. ¿Qué propósito cumple el patrón MVC en el desarrollo de software?

2. En el proyecto MVC descrito, ¿cuál es el nombre de la base de datos creada en MySQL?

3. ¿Qué campo de la tabla 'productos' en la base de datos tiene la propiedad de autoincremento?

4. ¿Qué archivo actúa como punto de entrada principal en el proyecto MVC?

5. En el archivo config.php, ¿qué constante define la URL base del proyecto?

6. ¿Qué tecnología se usa en el modelo para conectar con la base de datos MySQL?

7. En el controlador, ¿qué método se encarga de mostrar la lista de productos?

8. ¿Qué función realiza el método 'insertar' en el modelo?

9. En la vista index.php, ¿qué archivo se incluye para mostrar el encabezado de la página?

10. ¿Qué clase CSS en app.css define el ancho del contenedor principal (.panel)?

11. ¿Qué parámetro en la URL determina qué método del controlador se ejecuta?

12. En el método 'mostrar' del modelo, ¿qué método de PDO se usa para obtener los resultados de la consulta?

13. ¿Qué acción realiza el método 'guardar' en el controlador?

14. En la vista editar.php, ¿qué campo oculto se usa para enviar el ID del producto?

15. ¿Qué propiedad CSS en app.css aplica una sombra al contenedor principal (.panel)?

CÓDIGO FUENTE: USD 5.00

Conversar con J.Luis

Codea Applications

México, Colombia, España, Venezuela, Argentina, Bolivia, Perú