Ir al contenido principal

Altas

Qué es un alta

Un alta agrega una fila nueva a una tabla. Es la operación que hace crecer la base: hasta que no hay altas, la tabla está vacía y no hay nada que listar, modificar ni dar de baja.

Es la más sencilla de las cuatro —no hay que buscar nada, solo agregar— y por eso es la primera que se programa. Pero es también la más determinante, y ahí está la trampa: todo lo que entra por el alta es lo que va a haber después en la base. Un dato mal cargado en este momento va a haber que corregirlo con una modificación, o borrarlo con una baja; y si nadie se da cuenta, va a quedar ahí durante años.

De ahí que el alta sea la operación con más controles de todas, y que esos controles estén repartidos en tres lugares: en el formulario, eligiendo bien los controles para que el error sea difícil de cometer; en el servidor, validando todo otra vez porque lo que llega no es confiable; y en la base de datos, con los tipos y las restricciones que declaramos en el CREATE TABLE. Los tres son necesarios y ninguno alcanza solo.

La sentencia INSERT INTO

La sentencia que agrega un registro es INSERT INTO, y está desarrollada en la Unidad 3: su forma completa, la inserción de varios registros a la vez y la correspondencia entre cada valor y el tipo del campo.

INSERT INTO socios (nombre, documento, correo, alta)
VALUES ('Ana Pérez', '30123456', '[email protected]', '2026-05-12');

Lo que cambia cuando el alta viene de un formulario —y es lo propio de esta unidad— es que los valores ya no son constantes escritas por nosotros: son lo que escribió el usuario, que no sabemos de antemano. Eso convierte una línea de SQL en un pequeño programa con tres responsabilidades: conseguir los valores que llegaron, revisar que sean aceptables y mandar la inserción, solo si pasaron la revisión.

El id no aparece en la lista de campos, porque es AUTO_INCREMENT: la base le asigna el número siguiente sola. Y los campos que no se nombran toman su valor por defecto —activo queda en 1, como se declaró— o quedan vacíos si el campo lo admite.

El formulario que la dispara

El formulario de alta es el momento en que el usuario entrega los datos. Cada campo necesita su name, y ese name es lo único que conecta el formulario con el programa:

<form action="alta.php" method="post">
    <label for="nombre">Nombre y apellido</label>
    <input type="text" id="nombre" name="nombre" required>

    <label for="documento">Documento</label>
    <input type="text" id="documento" name="documento" required>

    <label for="correo">Correo electrónico</label>
    <input type="email" id="correo" name="correo">

    <button type="submit">Dar de alta</button>
</form>
En el formulario En el programa Qué es
name="nombre"$_POST['nombre']La clave con la que viaja el dato. Si no coinciden, el dato se pierde.
id="nombre"—Sirve para unir el label con el campo. El programa no lo ve.
<label>Nombre…—Lo que lee el usuario. Tampoco llega al programa.
method="post"$_POSTSi fuera GET, los datos llegarían en $_GET y en la dirección.

Ese cuadro explica el error número uno de los que empiezan con PHP: cambiar el name en el formulario y no cambiarlo en el programa —o al revés—. El formulario se ve perfecto, se envía sin error, y el dato no llega. PHP no avisa: si se pide una clave que no existe, devuelve un aviso y sigue, con lo cual el valor termina vacío y la fila se inserta igual, incompleta.

Ese código es el de los socios. Así se ve, en cambio, el mismo formulario en el CRUD de la tienda —el ejemplo completo, que se ejecuta de punta a punta— y lo que aparece después de guardar:

El formulario de alta del CRUD de la tienda: el menú arriba y el formulario Crear Producto con los campos Artículo, Descripción y Unidades Disponibles, y el botón verde Crear
El formulario del CRUD de la tienda. El menú de arriba lo pone index.php, que se incluye al principio del archivo; el formulario y su botón son propios de crear.php.
La pantalla del CRUD después de guardar un producto: el mensaje Producto creado con éxito y, debajo, el formulario vacío otra vez
Después de enviar. El mensaje confirma que se guardó y el formulario vuelve vacío, listo para cargar el siguiente producto: un alta no reemplaza la pantalla por un aviso, se queda donde estaba.

Esa segunda captura muestra una decisión que vale la pena notar: al terminar un alta, el programa no redirige al listado, sino que vuelve a mostrar el formulario con un mensaje. Es lo correcto cuando se van a cargar varios productos seguidos —cargar uno y volver al listado obligaría a entrar otra vez para cada uno—. Cuando el sistema atiende a una persona que carga un dato por vez, en cambio, conviene el otro camino: redirigir al listado, para que vea el resultado de lo que hizo.

El código PHP

Este es el programa completo del alta, con las tres responsabilidades en orden:

<?php

// 1. Conexión con la base
$bd = new PDO('mysql:host=localhost;dbname=biblioteca;charset=utf8mb4', 'usuario', 'clave');
$bd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// 2. Recibir los datos y limpiar los espacios sobrantes
$nombre    = trim($_POST['nombre']    ?? '');
$documento = trim($_POST['documento'] ?? '');
$correo    = trim($_POST['correo']    ?? '');

// 3. Validar EN EL SERVIDOR. Lo que llegó no es confiable.
$errores = [];

if ($nombre === '') {
    $errores[] = 'El nombre es obligatorio.';
}
if ($documento === '') {
    $errores[] = 'El documento es obligatorio.';
}
if ($correo !== '' && ! filter_var($correo, FILTER_VALIDATE_EMAIL)) {
    $errores[] = 'El correo no tiene un formato válido.';
}

// 4. Guardar solo si pasó la validación
if (! $errores) {

    $sentencia = $bd->prepare(
        'INSERT INTO socios (nombre, documento, correo, alta)
         VALUES (:nombre, :documento, :correo, :alta)'
    );

    $sentencia->execute([
        ':nombre'    => $nombre,
        ':documento' => $documento,
        ':correo'    => $correo,
        ':alta'      => date('Y-m-d'),
    ]);

    // 5. Redirigir (ver más abajo por qué)
    header('Location: listado.php?alta=ok');
    exit;
}

Cuatro cosas de ese código merecen atención:

  • trim() saca los espacios del principio y del final. Sin eso, un nombre escrito con un espacio al final se guarda con el espacio, y después no coincide en ninguna comparación. Es un detalle chico con consecuencias grandes.
  • $_POST['nombre'] ?? '' pide la clave, y si no existe usa un texto vacío. Sin el ?? '', si el campo no llegó —porque alguien armó la petición a mano— el programa avisa y sigue con un valor nulo.
  • La validación está en el servidor, con las mismas reglas que el required y el type="email" del formulario. No es duplicación inútil: es la única validación que el usuario no puede saltear.
  • La consulta usa marcadores para los valores. La explicación de esta técnica está en Inyección SQL y consultas preparadas.

Y hay una decisión de diseño: el date('Y-m-d') de la fecha de alta lo pone el programa, no el usuario. Tiene sentido: la fecha en que alguien se inscribe no es un dato que se le pregunte, es un dato del sistema. Cada vez que un valor se puede calcular en lugar de preguntarlo, conviene calcularlo: se elimina la posibilidad de que lo escriban mal.

Cómo saber si funcionó

Que el programa no haya dado error no significa que la fila se haya guardado. Para saberlo hay dos métodos que devuelven información sobre lo que acaba de pasar:

// ¿Cuántas filas se vieron afectadas?
$filas = $sentencia->rowCount();     // en un INSERT correcto vale 1

// ¿Qué número le tocó a la fila recién creada?
$id = $bd->lastInsertId();           // por ejemplo: 47
  • rowCount() devuelve cuántas filas afectó la operación. En un alta correcta vale 1. Si vale 0, no se insertó nada: algo pasó que hay que investigar.
  • lastInsertId() devuelve el número que la base le asignó al identificador autonumérico de la fila recién creada. Es imprescindible cuando el alta es solo el primer paso: si después hay que insertar un préstamo que apunta a ese socio, se necesita su id para ponerlo en la clave foránea —y ese número no se puede adivinar, porque lo decidió la base—.

Ojo con un detalle: lastInsertId() se tiene que pedir inmediatamente después del execute() y sobre la misma conexión. Si en el medio se ejecuta otra consulta, o se abre otra conexión, el valor que devuelve ya no es el que se busca.

Después de guardar: redirigir

Cuando el alta sale bien, el programa hace algo que a primera vista no tiene sentido: en lugar de mostrar una página de confirmación, manda al usuario a otra dirección.

header('Location: listado.php?alta=ok');
exit;

El motivo es el cartel que aparece cuando se recarga una página que se envió por POST: «¿Confirmar reenvío del formulario?». Si el alta terminara mostrando un mensaje, el usuario estaría mirando el resultado de un envío. Y si aprieta F5 —por costumbre, o porque quiere ver si el socio ya aparece en la lista— el navegador reenvía el formulario y se crea un segundo socio idéntico.

Redirigiendo, el usuario termina en otra página, que se obtuvo con un GET normal. Recargarla no reenvía nada: solo vuelve a pedir el listado. A este patrón se lo llama redirigir después de enviar, y es la solución estándar al problema del alta duplicada.

El exit de la línea siguiente no es opcional: header() solo anota la orden de redirigir, no detiene el programa. Si no se corta ahí, el resto del código se sigue ejecutando —y puede llegar a imprimir algo, lo que arruina la redirección—. Todo header('Location: ...') va seguido de exit.

Los errores típicos del alta

Qué falta Qué pasa
El name del formulario no coincide con el del programa El dato no llega y la fila se inserta incompleta, sin ningún error visible.
No se valida en el servidor Entra cualquier cosa: campos vacíos, textos donde van números, correos inventados.
No se usa trim() Se guardan espacios al principio o al final, y los datos dejan de coincidir en las comparaciones.
No se maneja el error de duplicado El usuario ve el error crudo de la base —«Duplicate entry…»— en lugar de un mensaje que entienda.
No se redirige después de guardar Recargar la página duplica el dato.

Vale mirar en detalle el error del documento duplicado, porque es el caso más común en un sistema real y muestra cómo se convierte un error técnico en un mensaje que sirve. La columna documento se declaró UNIQUE, así que la base va a rechazar el segundo socio con el mismo número. Y ese rechazo no hay que evitarlo: eso es la base funcionando bien.

try {
    $sentencia->execute([
        ':nombre'    => $nombre,
        ':documento' => $documento,
        ':correo'    => $correo,
        ':alta'      => date('Y-m-d'),
    ]);
} catch (PDOException $e) {
    // 23000 es el código de «se violó una restricción»
    if ($e->getCode() === '23000') {
        $errores[] = 'Ya hay un socio cargado con ese documento.';
    } else {
        $errores[] = 'No se pudo guardar el socio. Intentá de nuevo.';
    }
}

Los dos mensajes que se muestran son para el usuario. El texto real del error —«Duplicate entry '30123456' for key 'socios.documento'»— no dice nada útil a quien está cargando un socio, y además revela el nombre interno de la tabla y la restricción, que es información que no hace falta que circule. Traducir el error técnico a una frase entendible es parte del trabajo.

Resumen

  • Un alta agrega una fila nueva. Es la operación que hace crecer la tabla.
  • Es la más simple de programar y la más determinante: todo lo que hay después entró por acá.
  • Se usa INSERT INTO, sin poner el id si es autonumérico.
  • El name del formulario es la única conexión con $_POST['...']. Si no coinciden, el dato no llega.
  • El programa tiene tres responsabilidades: conseguir, revisar y mandar.
  • La validación del servidor es la única que no se puede saltear.
  • La técnica de consultas preparadas se explica en Inyección SQL.
  • rowCount() dice cuántas filas se afectaron; lastInsertId(), el número de la fila nueva.
  • Después de guardar se redirige, para que recargar no duplique el dato. Siempre con exit.
  • Un documento duplicado lo rechaza la base, y el error técnico hay que traducirlo a un mensaje entendible.

Ver las modificaciones