40-pintar con php
Validación de Disponibilidad de Habitaciones en un Sistema de Reservas Hotelero
En el desarrollo de un sistema de reservas para hoteles, una de las funcionalidades más críticas es la validación de disponibilidad de habitaciones. En este post, explicaré cómo implementamos esta característica en nuestro proyecto hotelero utilizando PHP y MySQL.
1. Primer Escenario: ¿Existe la habitación en la tabla reservas?
Objetivo: Verificar si la habitación seleccionada ya tiene reservas en la base de datos.
Estructura de la Base de Datos
Para gestionar las reservas, diseñamos tres tablas principales:
CREATE TABLE `reservas` (
`id_reserva` int(11) NOT NULL,
`id_habitacion` int(11) NOT NULL,
`id_usuario` int(11) NOT NULL,
`pago_reserva` float NOT NULL,
`numero_transaccion` text NOT NULL,
`codigo_reserva` text NOT NULL,
`descripcion_reserva` text NOT NULL,
`fecha_ingreso` date NOT NULL,
`fecha_salida` date NOT NULL,
`fecha_reserva` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `habitaciones` (
`id_h` int(11) NOT NULL,
`tipo_h` int(11) NOT NULL,
`estilo` text NOT NULL,
`galeria` text NOT NULL,
`video` text NOT NULL,
`recorrido_virtual` text NOT NULL,
`descripcion_h` text NOT NULL,
`fecha_h` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `categorias` (
`id` int(11) NOT NULL,
`ruta` text NOT NULL,
`color` text NOT NULL,
`tipo` text NOT NULL,
`img` text NOT NULL,
`descripcion` text NOT NULL,
`incluye` text NOT NULL,
`continental_alta` float NOT NULL,
`continental_baja` float NOT NULL,
`americano_alta` float NOT NULL,
`americano_baja` float NOT NULL,
`fecha` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;Flujo de Validación de Disponibilidad
El proceso de verificación de disponibilidad sigue estos pasos:
Recepción de datos: El sistema recibe el ID de la habitación y las fechas seleccionadas.
Consulta a la base de datos: Se realiza una consulta combinada (INNER JOIN) entre las tablas de habitaciones, reservas y categorías.
Análisis de resultados:
Si no hay coincidencias, la habitación está disponible.
Si hay coincidencias, se procede a verificar los rangos de fechas.
El proceso de validación sigue estos pasos:
Recolección de datos: El usuario selecciona una habitación y las fechas de ingreso/salida.
if(isset($_POST["id-habitacion"])){
$valor = $_POST['id-habitacion'];
$reservas = ControladorReservas::ctrMostrarReservas($valor);
}Consulta a la base de datos: Usamos un INNER JOIN entre las tablas para obtener información completa.
class ModeloReservas{
static public function mdlMostrarReservas($tabla1, $tabla2, $tabla3, $valor){
$stmt = Conexion::conectar()->prepare("SELECT $tabla1.*, $tabla2.*, $tabla3.* FROM $tabla1
INNER JOIN $tabla2 ON $tabla1.id_h = $tabla2.id_habitacion
INNER JOIN $tabla3 ON $tabla1.tipo_h = $tabla3.id WHERE id_h = :id_h");
$stmt -> bindParam(":id_h", $valor, PDO::PARAM_STR);
$stmt -> execute();
return $stmt -> fetchAll();
}
}Análisis de resultados:
Si no hay reservas para esa habitación, está disponible.
Si hay reservas, debemos comparar las fechas.
<?php if (!$reservas): ?>
<h1 class="pb-5 float-left">¡Está Disponible!</h1>
<?php else: ?>
<div class="infoDisponibilidad">
<!-- Aquí iría la lógica para comparar fechas -->
</div>
<?php endif ?>Controlador de Reservas
El controlador actúa como intermediario entre la vista y el modelo:
class ControladorReservas{
static public function ctrMostrarReservas($valor){
$tabla1 = "habitaciones";
$tabla2 = "reservas";
$tabla3 = "categorias";
$respuesta = ModeloReservas::mdlMostrarReservas($tabla1, $tabla2, $tabla3, $valor);
return $respuesta;
}
}
Primer Escenario: ¿Existe la habitación en reservas?
Objetivo: Verificar si la habitación seleccionada ya tiene reservas en la base de datos.
Consulta SQL con INNER JOIN:
Relacionamos 3 tablas:habitaciones,reservasycategoríaspara obtener toda la información relevante (precios, categoría, fechas, etc.).$respuesta = ReservasModel::buscarReservasPorHabitacion($id_habitacion); // Query: SELECT * FROM habitaciones // INNER JOIN reservas ON habitaciones.id = reservas.id_habitacion // INNER JOIN categorias ON habitaciones.tipo = categorias.idResultados:
Si la respuesta está vacía: La habitación está disponible.
Si hay datos: Debemos validar cruces de fechas (lo haremos después).
Visualización en la Interfaz
<?php if(!$reservas): ?>
<h1 class="pb-5 float-left">¡Está Disponible!</h1>
<?php else: ?>
<div class="infoDisponibilidad">Datos</div>
<?php endif ?>
<?php if(!$reservas): ?>
<h1 class="pb-5 float-left">¡Está Disponible!</h1>
<?php else: ?>
<div class="infoDisponibilidad">Datos</div>
<?php endif ?>2. Implementación en el Backend
Estructura del controlador (ReservasController):
class ReservasController {
public $id_habitacion; // Propiedad pública para recibir el ID
public function mostrarReservas() {
$respuesta = ReservasModel::buscarReservasPorHabitacion($this->id_habitacion);
echo json_encode($respuesta); // Envía datos a JavaScript
}
}Modelo (ReservasModel):
class ReservasModel {
static public function buscarReservasPorHabitacion($id_habitacion) {
// Conexión a BD y consulta con INNER JOIN
$stmt = Conexion::conectar()->prepare("...");
$stmt->bindParam(":id_habitacion", $id_habitacion, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}
}3. Integración con el Frontend
HTML:
Campos obligatorios para evitar envíos vacíos:
<select name="tipo_habitacion" required> <option value="">Seleccione una opción</option> <!-- Opciones dinámicas --> </select>
JavaScript:
Si la respuesta de la API está vacía, mostramos "Disponible":
if (respuesta.length === 0) { document.querySelector(".info-disponibilidad").innerHTML = "✅ Habitación disponible"; } else { // Lógica para cruce de fechas (próxima clase) }
4. Próximos Pasos
En la siguiente parte cubriremos:
🔹 Validación de fechas: Comparar fechas seleccionadas vs. reservas existentes.
🔹 Feedback visual: Mostrar mensajes claros ("Disponible" / "No disponible").
🔹 Optimización: Mejorar consultas SQL para reducir carga del servidor.
💡 ¿Por qué es importante?
Esta validación evita doble reserva de una misma habitación y mejora la experiencia del usuario.
Comentarios
Publicar un comentario