¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Trabajando con bases de datos en Laravel
A partir de la versión 11, cada proyecto nuevo de Laravel está configurado para trabajar con una base de datos SQLite.
Conexiones soportadas
Laravel soporta por defecto los siguientes motores de bases de datos:
- MariaDB
- MySQL
- PostgreSQL
- SQLite
- SQL Server
En el fichero config/database.php podemos ver los diferentes tipos de conexiones con bases de datos.
Conexión con bases de datos
SQLite
Fichero .env:
// ... DB_CONNECTION=sqlite #DB_HOST= #DB_PORT= #DB_DATABASE= #DB_USERNAME= #DB_PASSWORD=
Laravel, por defecto, asumirá que usaremos un fichero llamado database.sqlite que se almacenará en database/. En ese directorio crearemos el archivo.
MySQL
Una vez creada la base de datos MySQL, vamos a config/database.php. En cierto punto veremos que la conexión por defecto es a SQLite:
'default' => env('DB_CONNECTION', 'sqlite'),
La variable que vamos a cambiar, DB_CONNECTION está en el archivo .env, en la raíz del proyecto. Hacemos los siguientes cambios:
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=blog DB_USERNAME=root DB_PASSWORD=
Probaremos si la conexión es exitosa ejecutando unas migraciones:
php artisan migrate
Revisamos que se hayan creado nuevas tablas en nuestra base de datos de MySQL.
Migraciones
Son clases a partir de las cuales podemos crear o modificar tablas en la base de datos.
Si vamos a la carpeta database/migrations veremos 3 ficheros de migraciones:
database/migrations/xxxx_create_users_table.phpdatabase/migrations/xxxx_create_cache_table.phpdatabase/migrations/xxxx_create_jobs_table.php
Esas migraciones son las responsables de crear tablas. Por ejemplo, el fichero xxxx_create_users_table.php crearía las siguientes tablas:
userspassword_reset_tokenssesions
Ejecutar migraciones
php artisan migrate
Si ejecutamos migraciones de nuevo (sin haberlas borrado), Laravel no hará nada porque sabe que se ejecutó anteriormente porque mantiene una tabla llamada migrations con esa información.
Deshacer migraciones
php artisan migrate:rollback
Ese comando ejecutará el método down() de cada uno de los ficheros de migraciones para eliminar todas las tablas.
Crear migración
Para crear una migración que nos permita crear una tabla de productos:
php artisan make:migration create_posts_table
Esto habrá creado una migración, una clase anónima con los métodos up y down:
// ... public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->timestamps(); }); } public function down(): void { Schema::dropIfExists('posts'); }
La completamos a nuestro gusto:
// ... public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->longText('content'); $table->timestamps(); }); }
$table→timestamps() creará los campos created_at y updated_at.
Para ejecutar las migraciones:
php artisan migrate:fresh
El modificador fresh elimina todo de la base de datos. Es útil mientras desarrollamos, pero no deberíamos hacer eso nunca en producción. Si usamos el modificador rollback, solo borrará las migraciones del último lote (campo batch de la tabla migrations).
Existe el modificador refresh que no eliminaría las tablas creadas sin usar php artisan
Si tuviéramos un método para insertar datos:
php artisan migrate:fresh --seed
Modificar tablas
Si hacemos cambios en las tablas gestionadas por las migraciones, lo ideal es crear una nueva migración:
php artisan make:migration add_avatar_to_users_table
Esto creará un nuevo fichero de migración:
// ... public function up(): void { Schema::table('users', function (Blueprint $table) { }); } public function down(): void { Schema::table('users', function (Blueprint $table) { }); }
Y ahora lo modificaremos para añadir y quitar el campo:
// ... /** * Run the migrations */ public function up(): void { Schema::table('users', function (Blueprint $table) { $table->string('avatar')->nullable()->after('name'); // Para que se añada el campo después del campo 'name', usamos el método 'after' }); } /** * Reverse the migrations */ public function up(): void { Schema::table('users', function (Blueprint $table) { $table->dropColumn('avatar'); }); }
Ya podríamos usar el comando:
php artisan migrate
Eloquent
Eloquent es el ORM de Laravel. Un ORM (Object-Relational Mapping) se encarga de “mapear” / asociar la base de datos con estructuras de modelos que tengamos en nuestro sistema. El propósito es poder interactura con la base de datos como si fueran objetos dentro de la Programación Orientada a Objetos.
Modelos
La carpeta app/Models se incluyó por primera vez en la versión 8
En Laravel, los modelos y las tablas están estrechamente relacionados. Los modelos son el mecanismo de conexión entre nuestro código y la estructura de tablas y base de datos.
Un modelo es una clase y contiene la funcionalidad de los campos de la tabla a la que representa.
Hay varios tipos de atributos:
$fillable: atributos que se pueden asignar de manera masiva.$hidden: atributos que se ocultarán al recuperar información desde la base de datos.$casts: atributos que deben ser transformados a cierto tipo de dato.
Por defecto, Laravel toma como nombre de la tabla el nombre del modelo, pero en plural, es decir, si tenemos un modelo User, Laravel asumirá que la tabla será users.
Si no queremos seguir esa convención, añadiríamos al modelo el atributo $table asignándole como valor el nombre de la tabla.
La clase Model.php, que es de la que heredan los modelos que creamos, está en vendor/laravel/framework/src/Illuminate/Database/Eloquent/.
Creación de un modelo
Nos ayudamos de Artisan:
php artisan make:model Post
Esto habrá creado el modelo Post.php en app/Models/:
namespace App\Models; use Illuminate\Database\Eloquent\Model; class Post extends Model { }
Debemos indicarle qué tabla va a administrar:
// ... class Post extends Model { protected $table = 'posts'; }
Si la tabla se llama igual que la clase, pero en plural, no sería necesario crear la variable $table con el nombre de la tabla. Hay que tener en cuenta que Eloquent usa el inglés, hay que tenerlo en cuenta para que funcionen estas convenciones. Por ejemplo, si tenemos una tabla llamada “voces” y el modelo Voz, Eloquent esperará encontrarse una tabla llamada vozs.
Añadir registros
Si queremos añadir un registro:
$post = new Post; $post->title = "Título de prueba"; $post->content = "Contenido de prueba"; $post->save();
Editar registro
Si queremos editar un registro:
$post = Post::find(1); // Recuperamos el registro con ID 1 $post->title = "Nuevo título de prueba"; $post->save();
Podemos listar todos los posts atendiendo a cierto criterio:
$post = Post::orderBy('id', 'asc') ->select('id', 'title) ->take(2) // Limítalo a 2 registros ->get(); return $post;
Eliminar registro
Para eliminar un registro:
$post = Post::find(1); // Recuperamos el registro con ID 1 $post->delete();
Mutadores y accesores
Imaginemos que queremos que antes de meterse un valor en un campo, queremos tratarlo. Y también queremos tratarlo a la hora de recuperarlo. Para eso están los “mutadores” y “accesores”.
En el modelo que gestiona la tabla que tiene el campo que nos interesa, crearemos una función con el nombre del campo en cuestión:
// ... Use Illuminate\Database\Eloquent\Casts\Attribute; class Post extends Model { protected function title(): Attribute { return Attribute::make( set: function($value) { return strtolower($value); }, get: function($value) { return ucfirst($value); } ); } }
Con el código anterior, cuando se vaya a introducir un valor al campo title, se transformará antes a minúscula. Cuando vayamos a coger el valor del campo, se mostrará la primera letra en mayúscula.
Casting
Atributos de fecha con Carbon para facilitar operaciones como la diferencia de fechas, etc:
namespace App\Models; Use Illuminate\Database\Eloquent\Model; class Post extends Model { // Ahora indicamos qué campo debe ser transformado a una instancia de Carbon protected function casts(): array { return [ 'published_at' => 'datetime' ]; } }
Insertar información
Seeders
Factories
Los Factories permite generar automáticamente instancias de nuestros modelos.
En Laravel 8 hubo un cambio en la estructura y funcionamiento de los Factories
Por defecto, Laravel incluye el factory User en database/factories/UserFactory.php.
Los factories son clases con el nombre de un modelo y luego una definición donde indicamos cómo queremos rellenar los datos del modelo.
Para generar estos datos, Laravel se apoya en la biblioteca Faker que permite generar información aleatoria:
// code public function definition() { return [ 'name' => $this->faker->name(), 'email' => $this->faker->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), ]; }
Para crear nuestro propio factory, usaremos Artisan:
php artisan make:factory ProductFactory --model=Product
Hemos indicado que el factory que queremos crear es para el modelo Product. Tendremos que rellenar la definición de la factory recién creada:
public function definition() { return [ 'title' => $this->faker->sentence(3), 'description' => $this->faker->paragraph(1), 'price' => $this->faker->randomFloat($maxDecimals = 2, $min = 3, $max = 100), 'stock' => $this->faker->numberBetween(1, 10), 'status' => $this->faker->randomElement(['available', 'unavailable']) ]; }
Para que un modelo pueda usar un factory, hay que importar la definición HasFactory:
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Mdeol; class Cart extends Model { use HasFactory; // code }
Ahora usaremos este factory para crear de forma aleatoria instancias de nuestro producto. Usamos Artisan:
php artisan tinker
Y dentro de tinker:
App\Models\Product::factory()->count(5)->make();
Veremos las 5 instancias que se habrán creado. Como hemos usado make, no se habrá insertado en nuestra base de datos. Para ello, tendríamos que usar:
App\Models\Product::factory()->count(5)->create();
Database seeder
Podemos indicar por código cómo queremos crear instancias de nuestros modelos sin usar tinker.
Vamos a database/seeders/DatabaseSeeder.php:
public function run() { $products = Product::factory(5)->create(); }
Para ejecutar este seeder:
php artisan migrate:fresh --seed
Se crea de nuevo la base de datos y sus tablas y finalmente el seeder que ejecutará 5 instancias de Producto y las meterá en base de datos.
Si solo queremos ejecutar el seeder:
php artisan db:seed
Construyendo consultas a base de datos
Usando el Query Builder
Laravel dispone de un Query Builder que permite construir las consultas SQL para interactuar directamente con la base de datos.
Si queremos obtener toda la información de cierta tabla usando Query Builder:
use Illuminate\Support\Facades\DB; class ProductController extends Controller { public function index() { $products = DB::table("products")->get(); dd($products); } }
Cogiendo solo un elemento:
// code public function show($product) { $product = DB::table("products")->where("id", $product)->first(); dd($product); }
Podríamos abreviar la consulta usando el método find ya que buscará el primer elemento que coincida con el ID que indicamos:
// code $product = DB::table("products")->find($product);
Usando los modelos
Cualquier cosa que se pueda hacer con el Query Builder, también se puede hacer a través del modelo, y es lo recomendable (usando Eloquent).
La mayor utilidad de usar el modelo es su mantenimiento y escalabilidad del proyecto. Por ejemplo, si en algún momento se cambia el nombre de la tabla, usando el Query Builder, tendríamos que buscar en nuestro código todas las sentencias donde usamos el Query Builder con dicha tabla. Si usamos modelos, basta con hacer el cambio en el atributo $table del modelo.
Si queremos obtener una lista completa de productos usando el modelo y Eloquent (el ORM de Laravel):
use Illuminate\Support\Facades\DB; class ProductController extends Controller { public function index() { $products = Product::all(); dd($products); } }
Cogiendo solo un elemento:
// code public function show($product) { $product = Product::find($product); dd($product); }
Tenemos un método interesante para cuando no se encuentra lo que buscamos:
// code public function show($product) { $product = Product::findOrFail($product); // code }
Lo que hará findOrFail es lanzar una excepción que Laravel tratará como un error 404.
Si no lo usásemos y no existiera el producto, find devolvería NULL.
