====== 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]]