====== Desarrollo Web Lección 8 - Formularios ======
===== INSERT Consultas =====
==== Objetivo ====
* En esta actividad aprenderá cómo obtener datos de un formulario e insertarlos en una tabla de base de datos.
*
==== Configuración ====
* Continuaremos usando 'form.php' y 'process_form.php'. Si necesitas el código de nuevo, aquí está.
* [[https://techschool.murraygunn.id.au/webdev/classes/forms/4/form.es.php|form.php]]
* [[https://techschool.murraygunn.id.au/webdev/classes/forms/4/process_form.es.php|process_form.php]]
==== INSERTAR Consulta ====
* Para ver cómo funciona esto, comenzaremos en PHPMyAdmin.
* Inicie sesión y abra la tabla 'héroes' en la base de datos 'webdev'.
* Abra la pestaña 'Insertar'.
* Observe que cada uno de los campos de nuestra tabla está representado por una fila.
* Elija un héroe/villano de la siguiente lista y agréguelo a la tabla. Si estás trabajando en una clase, cada uno elige un personaje diferente.
^alias^identity^hero_villain^first_appeared^power^
|Thor|Thor Odinson|Hero|1962|Magic|
|Red Skull|Johan Schmidt|Villain|1941|Biological|
|Bucky Barnes|Winter Soldier|Villain|1941|Tech|
|Clint Barton|Hawkeye|Hero|1969|Skill|
|Odin|Odin|Hero|1962|Magic|
|Nick Fury|Nick Fury|Hero|1963|Skill|
|Phil Coulson|Agent Coulson|Hero|2008|Skill|
|Peter Quill|Starlord|Hero|1976|Tech|
|Gamora|Gamora|Hero|1975|Skill|
|Pepper Potts|Rescue|Hero|1963|Tech|
* Ingrese la información de su héroe en los campos apropiados en la columna 'Valor' y presione 'Ir'.
* Vea la consulta utilizada para agregar los datos justo debajo de la fila amarilla en la parte superior de la página.
INSERT INTO `heroes` (`alias`, `identity`, `hero_villain`, `first_appeared`, `power`) VALUES ('Bucky Barnes', 'Winter Soldier', 'Villain', '1941', 'Tech');
* Este es el formato que debemos usar para nuestra consulta de inserción en 'process_form.php'.
* Una consulta INSERT siempre comienza con 'INSERT INTO' y el nombre de la tabla que usaremos, luego una lista de los campos que queremos agregar.
* Esto es seguido por 'VALORES' y una lista de los valores a ser insertados.
==== Declaración de 'Switch' ====
* Recuerde que en realidad tenemos dos formularios enviados a esta página mediante dos botones de envío.
* Podemos identificar qué formulario procesar por el valor de '$_POST['submit']'.
* Podríamos hacer esto con una declaración 'si', como esta.
switch ($variable) {
case 'value':
# code...
break;
default:
# code...
break;
}
* Esto funcionaría, pero hay una mejor manera.
* Una 'sentencia switch' no es tan flexible como una 'sentencia if', que permite condiciones completamente nuevas en cada línea, pero es más potente a su manera.
* Abra 'process_form.php' en Visual Studio Code.
* Al final del primer bloque de PHP, escriba 'cambiar' y seleccione la segunda opción. Agregará el siguiente código automáticamente.
switch ($edad) {
case 1:
case 17:
case 43:
# code...
break;
case 22:
case 39:
# code...
break;
}
* Queremos ejecutar una consulta diferente dependiendo del valor de $_POST['submit'], así que reemplace '$variable' con $_POST['submit'].
* Ahora configure un caso para 'Agregar héroe' y 'Agregar apariencia'.
switch ($_POST['submit']) {
case 'Agregar Héroe':
break;
case 'Agregar apariencia':
break;
default:
break;
}
* Inserte nuestro código que usamos para ejecutar consultas de base de datos después de case 'Agregar Héroe':.
$query = "";
$args = array();
$rslt = $pdo->prepare($query);
$rslt->execute($args)
* Ahora podemos copiar nuestra consulta de PHPMyAdmin a la cadena de consulta.
* Debido a que los piratas informáticos pueden realizar una "inyección SQL" para obtener información sobre su base de datos o incluso para agregarse como un usuario administrador agregando código SQL como datos, vamos a eliminar los datos de nuestra consulta.
* Reemplace cada valor con ? luego agregue la entrada de usuario respectiva como elementos en la matriz '$args'.
$query = "INSERT INTO `heroes` (`alias`, `identity`, `hero_villain`, `first_appeared`, `power`) VALUES (?,?,?,?,?)";
$args = array($_POST['alias'], $_POST['identity'], $_POST['alias'], $_POST['side'], $_POST['year'], $_POST['power']);
* Este código funcionará a menos que haya un problema para acceder a la base de datos o una entrada de usuario no válida.
* Como queremos saber si hay un problema y decirle al usuario, agreguemos una verificación.
* Cambie $rslt->execute($args) a lo siguiente.
if ($rslt->execute($args)) {
} else {
}
* Agregue un mensaje en este bloque de código.
if ($rslt->execute($args)) {
$message = "{$_POST['name']} was inserted successfully.";
} else {
$message = "There was a problem inserting {$_POST['name']}.";
}
* El primer mensaje se mostrará cuando la consulta se haya ejecutado correctamente.
* El segundo mensaje se mostrará si no lo fue.
==== Insertos Múltiples ====
* El formulario Agregar apariencias permite al usuario agregar varias películas, pero cada una es su propia línea en la tabla de la base de datos.
* Podríamos crear una consulta separada para cada película, pero también es posible agregar varias líneas en la misma consulta haciendo algo como esto.
INSERT INTO appearances (character_name, movie) VALUES ('Thor Odinson', 'Thor: Dark World'), ('Thor Odinson', 'Avengers: Age of Ultron')
==== Empuje de Matriz ====
* Dejemos la consulta para el final porque necesitaremos filtrar las apariencias ya existentes.
* Primero, construyamos nuestro conjunto de argumentos: un par para cada película.
* Cada par de argumentos es el nombre de nuestro héroe y el nombre de la película, lo que podemos hacer en 'foreach' bucle.
foreach($_POST['movie'] as $movie) {
}
* Y podemos agregarlos a una matriz existente usando la 'array_push' función.
array_push($args, $_POST['hero'], $movie);
* El primer parámetro de esta función debe ser una matriz, y los valores posteriores se agregan al final de la matriz.
* Por supuesto, primero debemos crear la matriz, y no queremos que se vuelva a crear cada vez que hacemos un bucle, por lo que debemos crearla antes foreach.
$args = array();
foreach($_POST['movie'] as $movie) {
array_push($args, $_POST['hero'], $movie);
}
* Pero no queremos agregar películas que ya están incluidas en la base de datos, por lo que primero debemos verificar si existen.
// check if it exists already
$mquery = "SELECT * FROM appearances WHERE character_name=? AND movie=?";
$margs = array($_POST['hero'], $movie);
$rslt = $pdo->prepare($mquery);
$rslt->execute($margs);
if (!$row = $rslt->fetch()) {
array_push($args, $_POST['hero'], $movie);
}
* ¿Puedes leer este código por ti mismo?
* $mquery es la consulta que pregunta si el par héroe/película ya existe.
* $margs es la matriz de parámetros para la consulta.
* Luego ejecutamos la consulta y, si no existe (if (!$row = $rslt->fetch())), la agregamos a la lista de argumentos.
* ¿Y si es una nueva película? No queremos agregar la palabra 'nuevo' como título de la película. Tenemos que cambiarlo a $_POST['new_movie'] su lugar.
* Verifiquemos usando una 'sentencia if'.
if ($movie == 'new') {
array_push($args, $_POST['hero'], $_POST['new_movie']);
} else {
// check if it exists already
$mquery = "SELECT * FROM appearances WHERE character_name=? AND movie=?";
$margs = array($_POST['hero'], $movie);
$rslt = $pdo->prepare($mquery);
if (!$rslt->execute($margs)) {
array_push($args, $_POST['hero'], $movie);
}
}
* Si es nuevo, lo usamos $_POST['new_movie']como el nombre de la película en lugar del valor almacenado en $_POST['movie'].
==== Contar ====
* Podríamos haber creado la consulta primero y agregado piezas en el bucle, pero hay una forma más elegante.
* Si sabemos cuántas películas se han agregado, simplemente podemos agregar el número correcto (?,?) al final de la consulta.
* Podemos obtener el número de elementos en la $args matriz usando count y luego reducirlo a la mitad.
* count es como .length en Javascript, contando el número de elementos en una matriz.
* Agregue el siguiente código después del foreach bucle.
$movies = count($args)/2;
==== Cadena Repetitiva ====
* Luego, debemos agregar exactamente esa cantidad de copias de (?,?) al final de la consulta, pero deben estar separadas por un , .
$values = str_repeat('(?,?), ', $movies-1) . '(?,?)';
* Esta técnica utiliza una función llamada str_repeat para repetir una cadena establecida varias veces. Si repetimos '(?,?),' el número correcto de veces, tendríamos un colgante , al final que provocaría un error. En cambio, agregamos uno menos que la cantidad requerida ( count($movies) -1), luego agregamos (?,?) al final.
* Ahora, nuestra consulta es:
$query = "INSERT INTO heroes ('alias', 'movie') VALUES $values";
* Antes de ejecutar nuestra consulta, debemos verificar que el código funcione, que tanto la consulta como los argumentos se vean como deberían.
* Agregue lo siguiente antes de break.
error_log("MURRAY: $query\n" . print_r($args, 1);
* Guarde y cargue el código, luego abra 'form.php' en su navegador.
* Elija un héroe y seleccione una serie de películas, incluida la nueva. Ingrese una película que aún no esté en nuestra lista en ningún lugar y haga clic en 'Agregar apariencia'.
* Ahora verifique los registros de errores en Putty.
* Si la matriz de consultas y argumentos se ve bien, es hora de enviarlos a la base de datos.
$rslt = $pdo->prepare($query);
if ($rslt->execute($args)) {
$message = "$movies appearances were inserted successfully.";
} else {
$message = "There was a problem inserting $movies appearances.";
}
* Este código también incluye la verificación para ver si la consulta fue exitosa y agrega un mensaje apropiado en cualquier caso.
* Guarde y cargue su código, luego abra 'form.php' y envíe algunas apariencias nuevas para verificar que todo funcione.
* El único problema que aún tenemos es que si el usuario solo agrega películas que ya están en la base de datos, estamos creando una consulta e intentando enviarla sin valores.
* Arreglemos eso deteniéndonos si no hay nuevas películas para agregar.
if ($movies > 0) {
$values = str_repeat('(?,?), ', $movies-1) . '(?,?)';
$query = "INSERT INTO appearances (alias, movie) VALUES $values";
error_log("MURRAY: $query " . print_r($args, 1));
$rslt = $pdo->prepare($query);
if ($rslt->execute($args)) {
$message = "$movies appearances were inserted successfully.";
} else {
$message = "There was a problem inserting $movies appearances.";
}
} else {
$checked = count($_POST['movie']);
$message = "All $checked appearances are already in the database.";
}
* En lugar de referirme a $movies, que será 0 en este caso, cambié el mensaje para que se refiera al número original de películas enviadas e indique que ya estaban todas en la base de datos.
* Esta ha sido una gran actividad, pero hay más que hacer en la próxima actividad.
==== Codigo Final ====
* [[https://techschool.murraygunn.id.au/webdev/classes/forms/5/process_form.es.php|process_form.php]]
* [[https://techschool.murraygunn.id.au/webdev/classes/forms/5/form.php|resultado]]
[[es:web_development:forms:update|Siguiente: Consultas de UPDATE]]