One place for hosting & domains

      Cómo administrar y usar activadores de bases de datos de MySQL en Ubuntu 18.04


      El autor seleccionó la Apache Software Foundation para recibir una donación como parte del programa Write for DOnations.

      Introducción

      En MySQL, un activador es un comando SQL definido por el usuario que se invoca automáticamente durante una operación INSERT, DELETE o UPDATE. El código de activación se asocia con una tabla y se destruye una vez que se elimina una tabla. Puede especificar un tiempo de acción de activación y establecer si esta se producirá antes o después del evento de base de datos definido.

      Los activadores tienen varias ventajas. Por ejemplo, puede usarlos para generar el valor de una columna derivada durante una instrucción INSERT. Otro caso de uso tiene que ver con la aplicación de la integridad referencial, en el que puede usar un activador para guardar un registro en varias tablas relacionadas. Entre otras ventajas, se incluyen el registro de las acciones del usuario para realizar una auditoría de las tablas, así como la copia en vivo de datos en diferentes esquemas de bases de datos por motivos de redundancia para evitar un único punto de fallo.

      También puede usar activadores para mantener las reglas de validación en el nivel de base de datos. Esto le permite compartir la fuente de datos en varias aplicaciones sin infringir la lógica de negocios. Con esto, se reducen en gran medida los recorridos de ida y vuelta al servidor de base de datos, lo cual a su vez mejora el tiempo de respuesta de sus aplicaciones. Debido a que en el servidor de base de datos se ejecutan activadores, se pueden aprovechar recursos mejorados de este, como la memoria RAM y el CPU.

      En este tutorial, creará, usará y eliminará diferentes tipos de activadores en su base de datos de MySQL.

      Requisitos previos

      Antes de comenzar, asegúrese de contar con lo siguiente:

      Paso 1: Crear una base de datos de ejemplo

      En este paso, creará una base de datos de clientes de ejemplo con varias tablas para demostrar el funcionamiento de los activadores de MySQL.

      Para obtener más información sobre consultas de MySQL, lea nuestra Introducción a las consultas de MySQL.

      Primero, inicie sesión en su servidor MySQL como root:

      Introduzca su contraseña root de MySQL cuando se le solicite y presione INTRO para continuar. Cuando visualice el intérprete de comandos de mysql>, ejecute el siguiente comando para crear una base de datos test_db:

      Output

      Query OK, 1 row affected (0.00 sec)

      A continuación, realice un cambio a test_db con lo siguiente:

      Output

      Database changed

      Comience creando una tabla customers. En esta tabla se almacenarán los registros de los clientes, incluidos customer_id, customer_name y level. Habrá dos niveles de cliente: BASIC y VIP.

      • Create table customers(customer_id BIGINT PRIMARY KEY, customer_name VARCHAR(50), level VARCHAR(50) ) ENGINE=INNODB;

      Output

      Query OK, 0 rows affected (0.01 sec)

      Ahora, añada algunos registros a la tabla customers. Para hacer esto, ejecute los siguientes comandos uno por uno:

      • Insert into customers (customer_id, customer_name, level )values('1','JOHN DOE','BASIC');
      • Insert into customers (customer_id, customer_name, level )values('2','MARY ROE','BASIC');
      • Insert into customers (customer_id, customer_name, level )values('3','JOHN DOE','VIP');

      Verá el siguiente resultado después de ejecutar cada uno de los comandos INSERT:

      Output

      Query OK, 1 row affected (0.01 sec)

      Para asegurarse de que los registros de ejemplo se hayan insertado correctamente, ejecute el comando SELECT:

      Output

      +-------------+---------------+-------+ | customer_id | customer_name | level | +-------------+---------------+-------+ | 1 | JOHN DOE | BASIC | | 2 | MARY ROE | BASIC | | 3 | JOHN DOE | VIP | +-------------+---------------+-------+ 3 rows in set (0.00 sec)

      También creará otra tabla para contener información relacionada con la cuenta customers. Esta tabla contendrá un campo customer_id y un campo status_notes.

      Ejecute el siguiente comando:

      • Create table customer_status(customer_id BIGINT PRIMARY KEY, status_notes VARCHAR(50)) ENGINE=INNODB;

      A continuación, creará una tabla sales. En esta tabla, se almacenarán datos de ventas relacionados con los diferentes clientes a través de la columna customer_id:

      • Create table sales(sales_id BIGINT PRIMARY KEY, customer_id BIGINT, sales_amount DOUBLE ) ENGINE=INNODB;

      Output

      Query OK, 0 rows affected (0.01 sec)

      En los próximos pasos, añadirá datos de ejemplo a los de sales mientras prueba los activadores. A continuación, cree una tabla audit_log para registrar las actualizaciones realizadas en la tabla sales cuando implemente el activador AFTER UPDATE en el paso 5:

      • Create table audit_log(log_id BIGINT PRIMARY KEY AUTO_INCREMENT, sales_id BIGINT, previous_amount DOUBLE, new_amount DOUBLE, updated_by VARCHAR(50), updated_on DATETIME ) ENGINE=INNODB;

      Output

      Query OK, 0 rows affected (0.02 sec)

      Una vez establecidas la base de datos test_db y las cuatro tablas, procederá a trabajar con los diferentes activadores de MySQL en su base de datos.

      Paso 2: Crear un activador “Before Insert”

      En este paso, examinará la sintaxis de un activador de MySQL antes de aplicar esta lógica para crear un activador BEFORE INSERT que valide el campo sales_amount cuando se inserten datos en la tabla sales.

      La sintaxis general para crear un activador de MySQL se muestra en el siguiente ejemplo:

      DELIMITER //
      CREATE TRIGGER [TRIGGER_NAME]
      [TRIGGER TIME] [TRIGGER EVENT]
      ON [TABLE]
      FOR EACH ROW
      [TRIGGER BODY]//
      DELIMITER ;
      

      En la estructura del activador se incluye lo siguiente:

      DELIMITER //: el delimitador predeterminado de MySQL es ;, es necesario cambiarlo por algo diferente para que MySQL trate las siguientes líneas como un comando hasta que alcance su delimitador personalizado. En este ejemplo, el delimitador se cambió a // y luego al final se redefinió el delimitador ;.

      [TRIGGER_NAME]: un activador debe contar con un nombre y aquí es donde debe incluir el valor.

      [TRIGGER TIME]: un activador se puede invocar en diferentes intervalos. En MySQL se le permite definir si el activador se iniciará antes o después de una operación de base de datos.

      [TRIGGER EVENT]: los activadores solo se pueden invocar con operaciones INSERT, UPDATE y DELETE. Aquí puede usar cualquier valor dependiendo de lo que quiera lograr.

      [TABLE]: cualquier activador que cree en su base de datos de MySQL debe estar asociado a una tabla.

      FOR EACH ROW: con esta instrucción se ordena a MySQL ejecutar el código de activación para cada fila afectada por el activador.

      [TRIGGER BODY]: el código que se ejecuta cuando se invoca el activador se conoce como cuerpo del activador. Puede constar de una sola instrucción SQL o de varios comandos. Tenga en cuenta que si ejecuta varias instrucciones SQL en el cuerpo del activador, debe ajustarlas entre un bloque BEGIN... END.

      Nota: Cuando cree el cuerpo del activador, puede usar las palabras claves OLD y NEW para acceder a los valores antiguos y nuevos de la columna introducidos durante una operación INSERT, UPDATE, y DELETE. En un activador DELETE, solo se puede emplear la palabra clave OLD (que usará en el paso 4).

      Ahora, creará su primer activador BEFORE INSERT. Este activador estará asociado con la tabla sales y se invocará antes de que se inserte un registro para validar sales_amount. La función del activador es verificar si el campo sales_amount que se inserta en la tabla “sales” es mayor que 10000 y mostrar un error si esto se evalúa a “true”.

      Asegúrese de haber iniciado sesión en el servidor de MySQL. Luego, introduzca los siguientes comandos MySQL uno por uno:

      • DELIMITER //
      • CREATE TRIGGER validate_sales_amount
      • BEFORE INSERT
      • ON sales
      • FOR EACH ROW
      • IF NEW.sales_amount>10000 THEN
      • SIGNAL SQLSTATE '45000'
      • SET MESSAGE_TEXT = 'Sale has exceeded the allowed amount of 10000.';
      • END IF//
      • DELIMITER ;

      Usará la instrucción IF...THEN...END IF para evaluar si la cantidad que se proporciona durante la instrucción INSERT se encuentra dentro de su rango. Con el activador se puede extraer el nuevo valor sales_amount proporcionado con la palabra clave NEW.

      Para mostrar un mensaje de error genérico, utilice las siguientes líneas a fin de informar al usuario sobre el error:

      SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Sale has exceeded the allowed amount of 10000.';
      

      A continuación, inserte un registro con un sales_amount de 11000 en la tabla sales para verificar si con el activador se detendrá la operación:

      • Insert into sales(sales_id, customer_id, sales_amount) values('1','1','11000');

      Output

      ERROR 1644 (45000): Sale has exceeded the allowed amount of 10000.

      Este error muestra que el código de activación funciona según lo previsto.

      Ahora, pruebe un nuevo registro con un valor de 7500 para verificar si el comando tendrá éxito:

      • Insert into sales(sales_id, customer_id, sales_amount) values('1','1','7500');

      Debido a que el valor se encuentra dentro del rango recomendado, verá el siguiente resultado:

      Output

      Query OK, 1 row affected (0.01 sec)

      Para confirmar que se insertaron los datos, ejecute el siguiente comando:

      En el resultado, se confirma que los datos se encuentran en la tabla:

      Output

      +----------+-------------+--------------+ | sales_id | customer_id | sales_amount | +----------+-------------+--------------+ | 1 | 1 | 7500 | +----------+-------------+--------------+ 1 row in set (0.00 sec)

      En este paso, probó activadores para validar datos antes de su inserción en una base de datos.

      A continuación, trabajará con el activador AFTER INSERT para guardar información relacionada en diferentes tablas.

      Paso 3: Crear un activador “After Insert”

      Los activadores AFTER INSERT se ejecutan cuando se insertan registros correctamente en una tabla. Esta funcionalidad puede utilizarse para ejecutar automáticamente otras lógicas relacionadas con los negocios. Por ejemplo, en una aplicación bancaria, con un activador AFTER INSERT se puede cerrar una cuenta de préstamo cuando un cliente termina de pagarlo. El activador puede controlar todos los pagos introducidos en una tabla de transacciones y cerrar el préstamo automáticamente una vez que el saldo llegue a cero.

      En este paso, trabajará con su tabla customer_status usando un activador AFTER INSERT para ingresar registros de clientes relacionados.

      Para crear el activador AFTER INSERT, introduzca los siguientes comandos:

      • DELIMITER //
      • CREATE TRIGGER customer_status_records
      • AFTER INSERT
      • ON customers
      • FOR EACH ROW
      • Insert into customer_status(customer_id, status_notes) VALUES(NEW.customer_id, 'ACCOUNT OPENED SUCCESSFULLY')//
      • DELIMITER ;

      Output

      Query OK, 0 rows affected (0.00 sec)

      Aquí, indica que MySQL guarde otro registro en la tabla customer_status una vez que se inserte un nuevo registro de cliente en la tabla customers.

      Ahora, inserte un nuevo registro en la tabla customers para confirmar que se invocará su código de activación.

      • Insert into customers (customer_id, customer_name, level )values('4','DAVID DOE','VIP');

      Output

      Query OK, 1 row affected (0.01 sec)

      Debido a que el registro se insertó correctamente, compruebe que se haya introducido un nuevo registro de estado en la tabla customer_status:

      • Select * from customer_status;

      Output

      +-------------+-----------------------------+ | customer_id | status_notes | +-------------+-----------------------------+ | 4 | ACCOUNT OPENED SUCCESSFULLY | +-------------+-----------------------------+ 1 row in set (0.00 sec)

      En el resultado se confirma que el activador se ejecutó correctamente.

      El activador AFTER INSERT es útil para controlar el ciclo de vida de un cliente. En un entorno de producción, las cuentas de los clientes pueden atravesar diferentes etapas, como la apertura, la suspensión y el cierre.

      En los siguientes pasos, trabajará con activadores UPDATE.

      Paso 4: Crear un activador “Before Update”

      Los activadores BEFORE UPDATE son similares a los BEFORE INSERT; la diferencia radica en el momento en que se invocan. Puede usar el activador BEFORE UPDATE para verificar una lógica de negocios antes de que se actualice un registro. Para probar esto, usará la tabla customers en la que ya insertó datos.

      Dispone de dos niveles para sus clientes en la base de datos. En este ejemplo, una vez que la cuenta de un cliente asciende al nivel VIP, ya no es posible que descienda al nivel BASIC. Para aplicar tal regla, creará un activador BEFORE UPDATE que se ejecutará antes de la instrucción UPDATE, como se muestra a continuación. Si un usuario de la base de datos intenta hacer que un cliente descienda al nivel BASIC desde el nivel VIP, se activará una excepción definida por el usuario.

      Introduzca los siguientes comandos SQL uno por uno para crear el activador BEFORE UPDATE:

      • DELIMITER //
      • CREATE TRIGGER validate_customer_level
      • BEFORE UPDATE
      • ON customers
      • FOR EACH ROW
      • IF OLD.level='VIP' THEN
      • SIGNAL SQLSTATE '45000'
      • SET MESSAGE_TEXT = 'A VIP customer can not be downgraded.';
      • END IF //
      • DELIMITER ;

      Utilice la palabra clave OLD para capturar el nivel que el usuario proporciona cuando ejecuta el comando UPDATE. Una vez más, utilice la instrucción IF...THEN…END IF“ para indicar una instrucción de error genérico al usuario.

      Luego, ejecute el siguiente comando SQL con el que se intenta bajar el nivel de la cuenta de un usuario asociado con el customer_id de 3:

      • Update customers set level='BASIC' where customer_id='3';

      Verá el siguiente resultado, en el que se muestra SET MESSAGE_TEXT:

      Output

      ERROR 1644 (45000): A VIP customer can not be downgraded.

      Si ejecuta el mismo comando en un cliente de nivel BASIC e intenta que la cuenta ascienda al nivel VIP, el comando se ejecutará correctamente:

      • Update customers set level='VIP' where customer_id='1';

      Output

      Rows matched: 1 Changed: 1 Warnings: 0

      Usó el activador BEFORE UPDATE para implementar una regla comercial. Ahora, usará un activador AFTER UPDATE para registros de auditoría.

      Paso 5: Crear un activador “After Update”

      Un activador AFTER UPDATE se invoca una vez que se actualiza correctamente el registro de una base de datos. Este comportamiento hace que el activador sea adecuado para los registros de auditoría. En un entorno multiusuario, es posible que el administrador quiera ver el historial de los usuarios que actualizan registros en una tabla en particular para auditorías.

      Creará un activador que registre la actividad de actualización de la tabla sales. Nuestra tabla audit_log contendrá información sobre los usuarios de MySQL que actualicen la tabla sales, la date de la actualización y los valores sales_amount de new y old.

      Para crear el activador, ejecute los siguientes comandos SQL:

      • DELIMITER //
      • CREATE TRIGGER log_sales_updates
      • AFTER UPDATE
      • ON sales
      • FOR EACH ROW
      • Insert into audit_log(sales_id, previous_amount, new_amount, updated_by, updated_on) VALUES (NEW.sales_id,OLD.sales_amount, NEW.sales_amount,(SELECT USER()), NOW() )//
      • DELIMITER ;

      Se ingresa un nuevo registro en la tabla audit_log. Utilice la palabra clave NEW para obtener el valor de sales_id y el nuevo sales_amount. Además, utilice la palabra clave OLD para obtener el sales_amount anterior, ya que desea registrar ambos montos para auditoría.

      Con el comando SELECT USER() se obtiene el usuario actual que realiza la operación y con la instrucción NOW() se obtiene el valor de la fecha y hora actuales del servidor de MySQL.

      Si ahora un usuario intenta actualizar el valor de cualquier registro en la tabla sales, el activador log_sales_updates insertará un nuevo registro en la tabla audit_log.

      Crearemos un nuevo registro de ventas con un sales_id aleatorio de 5 e intentaremos actualizarlo. Primero, inserte el registro de ventas con lo siguiente:

      • Insert into sales(sales_id, customer_id, sales_amount) values('5', '2','8000');

      Output

      Query OK, 1 row affected (0.00 sec)

      A continuación, actualice el registro:

      • Update sales set sales_amount='9000' where sales_id='5';

      Verá el siguiente resultado:

      Output

      Rows matched: 1 Changed: 1 Warnings: 0

      Ahora ejecute el siguiente comando para verificar si con el activador AFTER UPDATE se pudo introducir un nuevo registro en la tabla audit_log:

      En el activador se registró la actualización. En el resultado se muestran el sales_amount y el new amount anteriores registrados con el usuario que actualizó los registros:

      Output

      +--------+----------+-----------------+------------+----------------+---------------------+ | log_id | sales_id | previous_amount | new_amount | updated_by | updated_on | +--------+----------+-----------------+------------+----------------+---------------------+ | 1 | 5 | 8000 | 9000 | root@localhost | 2019-11-07 09:28:36 | +--------+----------+-----------------+------------+----------------+---------------------+ 1 row in set (0.00 sec)

      También dispone de la fecha y hora en las que se realizó la actualización, que son valiosas para auditorías.

      A continuación, usará el activador DELETE para aplicar la integridad referencial a nivel de base de datos.

      Paso 6: Crear un activador “Before Delete”

      Los activadores BEFORE DELETE se invocan antes de que se ejecute una instrucción DELETE en una tabla. Estos tipos de activadores normalmente se utilizan para implementar la integridad referencial en diferentes tablas relacionadas. Por ejemplo, cada registro de la tabla sales se relaciona a un customer_id de la tabla customers. Si un usuario de la base de datos eliminara un registro de la tabla customers que tiene un registro relacionado en la tabla sales, usted no tendría manera de conocer al cliente asociado a ese registro.

      A fin de evitar esto, puede crear un activador BEFORE DELETE para aplicar su lógica. Ejecute los siguientes comandos SQL uno por uno:

      • DELIMITER //
      • CREATE TRIGGER validate_related_records
      • BEFORE DELETE
      • ON customers
      • FOR EACH ROW
      • IF OLD.customer_id in (select customer_id from sales) THEN
      • SIGNAL SQLSTATE '45000'
      • SET MESSAGE_TEXT = 'The customer has a related sales record.';
      • END IF//
      • DELIMITER ;

      Ahora, intente eliminar un cliente que tenga un registro de ventas relacionado:

      • Delete from customers where customer_id='2';

      Como resultado, obtendrá lo siguiente:

      Output

      ERROR 1644 (45000): The customer has a related sales record.

      Con el activador BEFORE DELETE se puede evitar la eliminación accidental de información relacionada en una base de datos.

      Sin embargo, en algunas situaciones, es posible que quiera eliminar todos los registros asociados con un registro específico de las diferentes tablas relacionadas. En este caso, usaría el activador AFTER DELETE, que probará en el siguiente paso.

      Paso 7: Crear un activador “After Delete”

      Los activadores AFTER DELETE funcionan una vez que se elimina correctamente un registro. Un ejemplo de cómo puede usar un activador AFTER DELETE es una situación en la cual el nivel de descuento que recibe un cliente en particular se determina mediante el número de ventas realizadas durante un período definido. Si alguno de los registros del cliente se eliminan de la tabla sales, el nivel de descuento de este deberá reducirse.

      Otro uso del activador AFTER DELETE consiste en eliminar información relacionada de otra tabla una vez que se elimina un registro de una tabla básica. Por ejemplo, establecerá un activador con el que se elimine el registro del cliente si los registros de ventas con los customer_id relacionados se eliminan de la tabla sales. Ejecute el siguiente comando para crear su activador:

      • DELIMITER //
      • CREATE TRIGGER delete_related_info
      • AFTER DELETE
      • ON sales
      • FOR EACH ROW
      • Delete from customers where customer_id=OLD.customer_id;//
      • DELIMITER ;

      A continuación, ejecute lo siguiente para eliminar todos los registros de ventas asociados con un customer_id de 2:

      • Delete from sales where customer_id='2';

      Output

      Query OK, 1 row affected (0.00 sec)

      Ahora compruebe si hay registros para el cliente en la tabla sales:

      • Select * from customers where customer_id='2';

      Obtendrá un resultado Empty Set, ya que el activador eliminó el registro del cliente asociado con el customer_id de 2:

      Output

      Empty set (0.00 sec)

      Con esto, habrá usado cada una de las diferentes formas de activadores para realizar funciones específicas. A continuación, verá la manera de eliminar un activador de la base de datos si ya no lo necesita.

      Paso 8: Eliminar activadores

      Con un método similar al que se emplea para cualquier otro objeto de base de datos, puede eliminar los activadores usando el comando DROP. A continuación, se muestra la sintaxis para eliminar un activador:

      Drop trigger [TRIGGER NAME];
      

      Por ejemplo, para eliminar el último activador AFTER DELETE que creó, ejecute el siguiente comando:

      • Drop trigger delete_related_info;

      Output

      Query OK, 0 rows affected (0.00 sec)

      La necesidad de eliminar los activadores surge cuando desea recrear su estructura. En tal caso, puede eliminar el activador y redefinir uno nuevo con los diferentes comandos de activación.

      Conclusión

      A través de este tutorial, creó, utilizó y eliminó los diferentes tipos de activadores de una base de datos de MySQL. Usando un ejemplo de base de datos relacionada con los clientes, implementó activadores para diferentes casos de uso, como la validación de datos, la aplicación de lógica de negocios, el registro de auditorías y la aplicación de integridad referencial.

      Para obtener más información sobre el uso de su base de datos de MySQL, consulte lo siguiente:



      Source link

      Cómo usar migraciones y alimentadores de bases de datos para abstraer la configuración de bases de datos en Laravel


      Las migraciones y los sembradores son poderosas utilidades de bases de datos que se proporcionan a través del marco PHP Laravel para permitir a los desarrolladores iniciar, destruir y volver a crear rápidamente la base de datos de una aplicación. Estas utilidades permiten minimizar los problemas de inconsistencia que pueden surgir en la base de datos cuando varios desarrolladores trabajan en la misma aplicación: los nuevos colaboradores solo deben ejecutar un par de comandos artisan para configurar la base de datos en una nueva instalación.

      A lo largo de esta guía, crearemos migraciones y alimentadores para completar una base de datos de aplicación de demostración de Laravel con datos de ejemplo. Al final, podrá destruir y volver a crear las tablas de su base de datos cuantas veces lo desee, usando solo comandos artisan.

      Requisitos previos

      Para completar los pasos de esta guía, necesitará lo siguiente:

      Nota: En esta guía, para ejecutar la aplicación usaremos un entorno de desarrollo en contenedor administrado por Docker Compose, pero también puede optar por ejecutar la aplicación en un servidor LEMP. Para configurarlo, puede seguir nuestra guía Cómo instalar y configurar Laravel con LEMP en Ubuntu 18.04.

      Paso 1: Obtener la aplicación de demostración

      Para comenzar, obtendremos la aplicación Laravel de demostración de su repositorio de GitHub. Nos interesa la ramificación tutorial-02, en la que se incluye una configuración de Docker Compose para ejecutar la aplicación en contenedores. En este ejemplo, descargaremos la aplicación en nuestra carpeta de inicio, pero puede usar cualquier directorio que elija:

      • cd ~
      • curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-2.0.1.zip -o travellist.zip

      Debido a que descargamos el código de la aplicación como un archivo .zip, necesitaremos el comando unzip para desempaquetarlo. Si no lo hizo recientemente, actualice el índice local de paquetes de su computadora:

      A continuación instale el paquete unzip:

      Después de eso, descomprima el contenido de la aplicación:

      Luego para facilitar el acceso cambie el nombre del directorio desempaquetado por travellist-demo:

      • mv travellist-laravel-demo-tutorial-2.0.1 travellist-demo

      En el siguiente paso, crearemos un archivo de configuración .env para configurar la aplicación.

      Paso 2: Configurar el archivo .env de la aplicación

      En Laravel, se utiliza un archivo .env para establecer configuraciones dependientes del entorno, como las credenciales y cualquier información que pueda variar entre las implementaciones. Este archivo no está incluido en el control de revisiones.

      Advertencia: En el archivo de configuración del entorno se encuentra información confidencial sobre su servidor, incluidas las credenciales de bases de datos y las claves de seguridad. Por ese motivo, nunca debe compartir públicamente este archivo.

      Los valores incluidos en el archivo .env tendrán prioridad sobre los valores establecidos en los archivos de configuración normales que se encuentran en el directorio config. Para cada instalación en un nuevo entorno se requiere un archivo de entorno personalizado a fin de definir elementos como las configuraciones de conexión de bases de datos, las opciones de depuración y las URL de aplicación, entre otros elementos que pueden variar dependiendo del entorno en el que se ejecute la aplicación.

      Diríjase al directorio travellist-demo:

      Ahora, crearemos un nuevo archivo .env para personalizar las opciones de configuración para el entorno de desarrollo que configuraremos. En Laravel se incluye un archivo .env de ejemplo que podemos copiar para crear el nuestro:

      Abra este archivo utilzando nano o el editor de texto que prefiera:

      Así es como se ve su archivo .env ahora:

      .env

      APP_NAME=Travellist
      APP_ENV=dev
      APP_KEY=
      APP_DEBUG=true
      APP_URL=http://localhost:8000
      
      LOG_CHANNEL=stack
      
      DB_CONNECTION=mysql
      DB_HOST=db
      DB_PORT=3306
      DB_DATABASE=travellist
      DB_USERNAME=travellist_user
      DB_PASSWORD=password

      En el archivo .env actual de la aplicación de demostración travellist se incluyen las configuraciones para usar el entorno en contenedor que creamos con Docker Compose en la última parte de esta serie. No necesita cambiar ninguno de estos valores, pero puede modificar DB_DATABASE, DB_USERNAME y DB_PASSWORD si lo desea, ya que nuestro archivo docker-compose.yml los obtiene automáticamente para configurar la base de datos de desarrollo. Solo asegúrese de que la variable DB_HOST permanezca sin cambios, ya que esta hace referencia al nombre de nuestro servicio de base de datos dentro del entorno de Docker Compose.

      Si realiza algún cambio en el archivo, asegúrese de guardarlo y cerrarlo presionando CTRL + X, Y y luego INTRO.

      Nota: Si optó por ejecutar la aplicación en un servidor LEMP, deberá cambiar los valores resaltados para reflejar la configuración de su propia base de datos, incluida la variable DB_HOST.

      Paso 3: Instalar las dependencias de la aplicación con Composer

      Ahora usaremos Composer, la herramienta de administración de dependencias de PHP, para instalar las dependencias de la aplicación y garantizar que podamos ejecutar comandos artisan.

      Abra su entorno de Docker Compose con el comando siguiente. Con esto, se creará la imagen travellist para el servicio app y se extraerán las imágenes adicionales de Docker requeridas por los servicios de nginx y db a fin de crear el entorno de la aplicación:

      Output

      Creating network "travellist-demo_travellist" with driver "bridge" Building app Step 1/11 : FROM php:7.4-fpm ---> fa37bd6db22a Step 2/11 : ARG user ---> Running in 9259bb2ac034 … Creating travellist-app ... done Creating travellist-nginx ... done Creating travellist-db ... done

      Esta operación puede tardar unos minutos en completarse. Una vez terminado el proceso, podemos ejecutar Composer para instalar las dependencias de la aplicación.

      Para ejecutar composer y otros comandos en el contenedor de servicio app, usaremos docker-compose exec. El comando exec nos permite ejecutar cualquier comando que elijamos en los contenedores gestionados por Docker Compose. Se utiliza la siguiente sintaxis: docker-compose exec service_name command.

      Nota: En caso de optar por utilizar un servidor LEMP para ejecutar la aplicación de demostración, debe ignorar la parte de docker-compose exec app de los comandos enumerados a lo largo de esta guía. Por ejemplo, en lugar de ejecutar el siguiente comando como está escrito, simplemente ejecutaría lo siguiente:

      Para ejecutar composer install en el contenedor app, ejecute lo siguiente:

      • docker-compose exec app composer install

      Output

      Loading composer repositories with package information Installing dependencies (including require-dev) from lock file Package operations: 85 installs, 0 updates, 0 removals - Installing doctrine/inflector (1.3.1): Downloading (100%) - Installing doctrine/lexer (1.2.0): Downloading (100%) - Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%) …

      Cuando Composer termine de instalar las dependencias de la aplicación, podrá ejecutar los comandos artisan. Para verificar que en la aplicación se pueda establecer conexión con la base de datos, ejecute el siguiente comando en el que se eliminará cualquier tabla existente:

      • docker-compose exec app php artisan db:wipe

      Con este comando se eliminará cualquier tabla ya existente de la base de datos configurada. Si se ejecutó con éxito y en la aplicación se pudo establecer conexión con la base de datos, verá un resultado como el siguiente:

      Output

      Dropped all tables successfully.

      Ahora que instaló las dependencias de la aplicación con Composer, puede usar la herramienta artisan para crear migraciones y alimentadores.

      Paso 4: Crear migraciones de bases de datos

      En la herramienta de línea de comandos artisan que se incluye con Laravel hay una serie de comandos auxiliares que pueden utilizarse para administrar la aplicación e iniciar nuevas clases. Para generar una nueva clase de migración, podemos usar el comando make:migration de la siguiente manera:

      • docker-compose exec app php artisan make:migration create_places_table

      Laravel infiere la operación que se ejecutará (create), el nombre de la tabla (places) y si en esta migración se creará una tabla nueva o no, basada en el nombre descriptivo proporcionado al comando make:migration.

      Verá un resultado similar a este:

      Output

      Created Migration: 2020_02_03_143622_create_places_table

      Con esto se generará un nuevo archivo en el directorio database/migrations de la aplicación. Laravel utiliza la marca de tiempo incluida en el archivo generado automáticamente para determinar el orden en que se deben ejecutar las migraciones.

      Utilice su editor de texto preferido para abrir el archivo de migración generado. Recuerde sustituir el valor resaltado por el nombre de su propio archivo de migración:

      • nano database/migrations/2020_02_03_143622_create_places_table.php

      En el archivo de migración generado se incluye una clase llamada CreatePlacesTable:

      database/migrations/2020_02_03_143622_create_places_table.php

      <?php
      
      use IlluminateDatabaseMigrationsMigration;
      use IlluminateDatabaseSchemaBlueprint;
      use IlluminateSupportFacadesSchema;
      
      class CreatePlacesTable extends Migration
      {
          /**
           * Run the migrations.
           *
           * @return void
           */
          public function up()
          {
              Schema::create('places', function (Blueprint $table) {
                  $table->bigIncrements('id');
                  $table->timestamps();
              });
          }
      
          /**
           * Reverse the migrations.
           *
           * @return void
           */
          public function down()
          {
              Schema::dropIfExists('places');
          }
      }
      
      

      En esta clase se incluyen dos métodos: up y down. Ambos métodos contienen código de arranque que puede ampliar para personalizar lo que ocurre cuando se ejecuta esa migración y también lo que sucede cuando se revierte.

      Modificaremos el método up para que en la tabla places se refleje la estructura que ya estamos usando en la versión actual de la aplicación:

      • id: campo de clave primaria.
      • name: nombre del lugar.
      • visited: indica si este lugar ya recibió visitas o no.

      En el constructor de esquemas de Laravel se exponen los métodos para crear, actualizar y eliminar tablas de una base de datos. En la clase Blueprint se define la estructura de la tabla y se proporcionan varios métodos para abstraer la definición de cada campo de la tabla.

      En el código generado automáticamente se establece un campo de id primario llamado id. En el método timestamps se crean dos campos datetime que las clases de base de datos subyacentes actualizan de manera automática cuando se insertan o actualizan datos dentro de la tabla. Además de estas, tendremos que incluir un campo name y otro visited.

      Nuestro campo name será del tipo string y nuestro campo visited estará configurado con el tipo boolean. También estableceremos un valor predeterminado 0 para el campo visited, de modo que si no se transmite ningún valor, significa que aún no se visitó el lugar. El método up tendrá ahora el siguiente aspecto:

      database/migrations/2020_02_03_143622_create_places_table.php

      …
          public function up()
          {
              Schema::create('places', function (Blueprint $table) {
                  $table->bigIncrements('id');
                  $table->string('name', 100);
                  $table->boolean('visited')->default(0);
                  $table->timestamps();
              });
          }
      …
      

      Nota: Puede encontrar la lista completa de tipos de columnas disponibles en la documentación de Laravel.

      Después de incluir las dos líneas resaltadas en su propia secuencia de comandos de migración, guarde y cierre el archivo.

      Su migración estará lista para ejecutarse a través de artisan migrate. Sin embargo, eso solo crearía una tabla vacía; también debemos poder insertar datos de ejemplo para desarrollo y pruebas. En el siguiente paso, veremos cómo hacerlo usando alimentadores de bases de datos.

      Paso 5: Crear alimentadores de bases de datos

      Un alimentador es una clase especial que se utiliza para generar e insertar datos de ejemplo (semillas) en una base de datos. Esta es una característica importante en los entornos de desarrollo, ya que le permite volver a crear la aplicación con una base de datos nueva usando valores de ejemplo que de otra manera tendría que insertar manualmente al volver a crear la base de datos.

      Ahora, usaremos el comando artisan a fin de generar una nueva clase de alimentador para nuestra tabla places llamada PlacesTableSeeder:

      • docker-compose exec app php artisan make:seeder PlacesTableSeeder

      Con el comando se creará un nuevo archivo llamado PlacesTableSeeder.php dentro del directorio database/seeds. Abra el archivo usando su editor de texto preferido:

      • nano database/seeds/PlacesTableSeeder.php

      El archivo PlacesTableSeeder.php generado automáticamente tiene el siguiente aspecto:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      
      class PlacesTableSeeder extends Seeder
      {
          /**
           * Run the database seeds.
           *
           * @return void
           */
          public function run()
          {
              //
          }
      }
      
      

      Nuestra nueva clase de alimentador contiene un método vacío llamado run. Este método se invocará cuando se ejecute el comando db:seed de Artisan.

      Debemos editar el método run para que se incluyan las instrucciones de inserción de datos de ejemplo en la base de datos. Usaremos el generador de consultas de Laravel para simplificar este proceso.

      El generador de consultas de Laravel ofrece una interfaz fluida para operaciones de bases de datos como la inseción, actualización, eliminación y recuperación de datos. También cuenta con elementos de protección contra ataques de inyección SQL. Está expuesto por la fachada DB, un proxy estático para las clases de base de datos subyacentes en el contenedor de servicio.

      Para comenzar, crearemos una variable de clase estática para contener todos los lugares de ejemplo que queramos insertar en la base de datos como matriz. Esto nos permitirá usar un bucle foreach para iterar todos los valores, insertando cada uno en la base de datos con el generador de consultas.

      Daremos a esta variable el nombre $places:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      
      class PlacesTableSeeder extends Seeder
      {
          static $places = [
              'Berlin',
              'Budapest',
              'Cincinnati',
              'Denver',
              'Helsinki',
              'Lisbon',
              'Moscow',
              'Nairobi',
              'Oslo',
              'Rio',
              'Tokyo'
          ];

      A continuación, tendremos que incluir una instrucción use en la parte superior de nuestra clase PlacesTableSeeder para facilitar la referencia a la fachada DB en el código:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      use IlluminateSupportFacadesDB;
      
      class PlacesTableSeeder extends Seeder
      …
      

      Ahora, podemos iterar los valores de la matriz $places usando un bucle foreach e insertar cada uno en nuestra tabla places con el generador de consultas:

      database/seeds/PlacesTableSeeder.php

      …
          public function run()
          {
              foreach (self::$places as $place) {
                  DB::table('places')->insert([
                      'name' => $place,
                      'visited' => rand(0,1) == 1
                  ]);
              }
          }
      
      

      El bucle foreach itera cada valor de la matriz estática $places. En cada iteración, usamos la fachada DB para insertar una nueva fila en la tabla places. Para el campo name, fijamos el nombre del lugar que acabamos de obtener de la matriz $places y para el campo visited marcamos un valor aleatorio de 0 o 1.

      Así es como se visualizará la clase PlacesTableSeeder completa después de todas las actualizaciones:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      use IlluminateSupportFacadesDB;
      
      class PlacesTableSeeder extends Seeder
      {
          static $places = [
              'Berlin',
              'Budapest',
              'Cincinnati',
              'Denver',
              'Helsinki',
              'Lisbon',
              'Moscow',
              'Nairobi',
              'Oslo',
              'Rio',
              'Tokyo'
          ];
      
          /**
           * Run the database seeds.
           *
           * @return void
           */
          public function run()
          {
              foreach (self::$places as $place) {
                  DB::table('places')->insert([
                      'name' => $place,
                      'visited' => rand(0,1) == 1
                  ]);
              }
          }
      }
      

      Guarde y cierre el archivo cuando termine de realizar estos cambios.

      Las clases de alimentadores no se cargan automáticamente en la aplicación. Debemos editar la clase principal DatabaseSeeder para incluir una invocación al alimentador que acabamos de crear.

      Abra el archivo database/seeds/DatabaseSeeder.php con nano o su editor favorito:

      • nano database/seeds/DatabaseSeeder.php

      La clase DatabaseSeeder se parece a cualquier otro sembrador: deriva de la clase Seeder y tiene un método run. Actualizaremos este método para incluir una invocación a PlacesTableSeeder.

      Actualice el método actual run dentro de su clase DatabaseSeeder eliminando la línea marcada con comentarios y reemplazándola por el siguiente código resaltado:

      database/seeds/DatabaseSeeder.php

      …
          public function run()
          {
              $this->call(PlacesTableSeeder::class);
          }
      ...
      

      Después de la actualización, la clase DatabaseSeeder completa tendrá el siguiente aspecto:

      database/seeds/DatabaseSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      
      class DatabaseSeeder extends Seeder
      {
          /**
           * Seed the application's database.
           *
           * @return void
           */
          public function run()
          {
              $this->call(PlacesTableSeeder::class);
          }
      }
      
      
      

      Guarde y cierre el archivo cuando termine de actualizar su contenido.

      Con esto, terminamos de preparar una migración y un alimentador para nuestra tabla places. En el siguiente paso, veremos la manera de ejecutarlos.

      Paso 6: Ejecutar migraciones y alimentadores de bases de datos

      Antes de continuar, debemos asegurarnos de que su aplicación esté lista y en funcionamiento. Configuraremos la clave de cifrado de la aplicación y luego accederemos a esta última desde un navegador para probar el servidor web.

      Para generar la clave de cifrado requerida por Laravel, puede usar el comando artisan key:generate:

      • docker-compose exec app php artisan key:generate

      Una vez generada la clave, podrá acceder a la aplicación orientando su navegador al nombre de host o a la dirección IP de su servidor en el puerto 8000:

      http://server_host_or_ip:8000
      

      Verá una página como la siguiente:

      Error de MySQL

      Esto significa que en la aplicación se puede establecer conexión con la base de datos, pero no se logró encontrar una tabla llamada places. Ahora crearemos la tabla places usando el siguiente comando migrate de Artisan:

      • docker-compose exec app php artisan migrate

      Verá un resultado similar a este:

      Output

      Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.06 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.06 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds) Migrating: 2020_02_10_144134_create_places_table Migrated: 2020_02_10_144134_create_places_table (0.03 seconds)

      Observará que se ejecutaron algunas otras migraciones junto con la migración create_places_table que configuramos. Estas migraciones se generan de forma automática cuando se instala Laravel. Aunque ahora no usaremos estas tablas adicionales, serán necesarias en el futuro cuando ampliemos la aplicación para tener usuarios registrados y tareas programadas. Por ahora, puede dejarlas como están.

      En este momento, nuestra tabla sigue vacía. Debemos ejecutar el comando db:seed para propagar la base de datos con nuestros lugares de ejemplo:

      • docker-compose exec app php artisan db:seed

      Con esto, se ejecutará nuestro alimentador y se insertarán los valores de ejemplo que definimos en nuestra clase PlacesTableSeeder. Verá un resultado similar a este:

      Output

      Seeding: PlacesTableSeeder Seeded: PlacesTableSeeder (0.06 seconds) Database seeding completed successfully.

      Ahora, vuelva a cargar la página de la aplicación en su navegador. Verá una página similar a la siguiente:

      Aplicación de demostración de Laravel

      Cuando necesite comenzar desde cero, podrá descartar todas sus tablas de la base de datos con lo siguiente:

      • docker-compose exec app php artisan db:wipe

      Output

      Dropped all tables successfully.

      Para ejecutar las migraciones de la aplicación y propagar las tablas con un solo comando, puede usar lo siguiente:

      • docker-compose exec app php artisan migrate --seed

      Output

      Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.06 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.07 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds) Migrating: 2020_02_10_144134_create_places_table Migrated: 2020_02_10_144134_create_places_table (0.03 seconds) Seeding: PlacesTableSeeder Seeded: PlacesTableSeeder (0.06 seconds) Database seeding completed successfully.

      Si quiere revertir una migración, puede ejecutar lo siguiente:

      • docker-compose exec app php artisan migrate:rollback

      Con esto, se activará el método down para cada clase de migración dentro de la carpeta migrations. Normalmente, se eliminarán todas las tablas que se crearon a través de las clases de migración y se dejarán solo las tablas que se puedan haber creado de forma manual. Verá resultados como este:

      Output

      Rolling back: 2020_02_10_144134_create_places_table Rolled back: 2020_02_10_144134_create_places_table (0.02 seconds) Rolling back: 2019_08_19_000000_create_failed_jobs_table Rolled back: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds) Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (0.02 seconds) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (0.02 seconds)

      El comando rollback es especialmente útil cuando se realizan cambios en los modelos de la aplicación y no se puede usar un comando db:wipe; por ejemplo, si varios sistemas dependen de la misma base de datos.

      Conclusión

      En esta guía, abordamos la forma de usar migraciones y alimentadores de bases de datos para facilitar la creación de bases de datos de desarrollo y la prueba de estas para una aplicación de Laravel 6.

      Como paso siguiente, podría intereserle consultar la documentación de Laravel para obtener más información sobre cómo usar el generador de consultas y modelos de Eloquent para abstraer aún más el esquema de la base de datos de su aplicación.



      Source link