En esta lección prepararemos un sencillo listado de productos con categoría utilizando Laravel y los diferentes componentes que provee el ORM Eloquent (modelos, migraciones, model factories y seeders).
Crear un nuevo proyecto con Laravel 6
Vamos a crear un nuevo proyecto de Laravel. Yo utilizaré la versión 6, pero los conocimientos de este tip están disponibles desde la versión 5.3 en adelante:
# composer create-project laravel/laravel fast_eloquent "6.*"
Generar modelos, factories y seeders con Laravel
Ahora vamos al directorio del proyecto y generemos 2 modelos con sus migraciones, model factories y seeders:
# cd fast_eloquent php artisan make:model ProductCategory -mfs php artisan make:model Product -mfs
Modificando las migraciones
En la migración de ProductCategory
vamos a agregar algunas columnas, las esenciales son title
y slug
, pero supongamos que requerimos de otras 5 columnas:
<?php //... class CreateProductCategoriesTable extends Migration { public function up() { Schema::create('product_categories', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('title'); $table->string('slug'); $table->mediumText('description'); // Agrega al menos 4 columnas extra $table->timestamps(); }); } //... }
La migración de la tabla de productos será similar, aunque vamos a incluir un campo para imágenes y también debemos incluir un campo para el ID de la categoría:
<?php //... class CreateProductsTable extends Migration { public function up() { Schema::create('products', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('category_id'); $table->string('title'); $table->string('slug'); $table->string('image'); $table->mediumText('description'); // Agrega al menos 3 columnas adicionales $table->timestamps(); }); } //... }
Modificando los Model Factories
Usemos Faker para generar datos aleatorios para ambos modelos:
Primero en database/factories/ProductCategoryFactory.php
:
<?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use App\ProductCategory; use Faker\Generator as Faker; $factory->define(ProductCategory::class, function (Faker $faker) { return [ 'title' => $faker->sentence(2), 'slug' => $faker->slug, 'description' => $faker->paragraph, // Continua con el resto de las columnas ]; });
Luego en database/factories/ProductFactory.php
, el proceso es similar en ambos factories:
<?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use App\Product; use Faker\Generator as Faker; $factory->define(Product::class, function (Faker $faker) { return [ 'category_id' => factory(\App\ProductCategory::class), 'title' => $faker->sentence(4), 'slug' => $faker->slug, 'image' => $faker->randomElement(['img1.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg']), 'description' => $faker->paragraph, ]; });
Modificando los Seeders
A continuación, modifiquemos los seeders para generar 50 categorías y alrededor de 1000 productos asociados a dichas categorías:
<?php use Illuminate\Database\Seeder; class ProductCategorySeeder extends Seeder { public function run() { factory(\App\ProductCategory::class)->times(200)->create(); } }
<?php use Illuminate\Database\Seeder; class ProductSeeder extends Seeder { public function run() { $categories = \App\ProductCategory::pluck('id'); $categories->each(function ($category) { factory(\App\Product::class)->times(rand(12, 28))->create([ 'category_id' => $category, ]); }); } }
No olvides agregar el llamado a los seeders dentro de DatabaseSeeder
:
<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { public function run() { $this->call([ProductCategorySeeder::class, ProductSeeder::class]); } }
Debes cargar los datos en el orden correcto, por ejemplo, los productos dependen de la categoría del producto, por lo tanto, cargamos las categorías de producto primero y luego los productos.
Crear tablas con datos en Laravel
Para ejecutar las migraciones y los seeders primero debemos configurar la base de datos, como vimos en la lección Creación de tablas con el sistema de migraciones en Laravel 6, simplemente edita el archivo .env
y modifica las siguientes llaves con los valores que correspondan a tu entorno:
### DB_CONNECTION=mysql DB_HOST=localhost DB_PORT=3306 DB_DATABASE=fast_eloquent DB_USERNAME=root DB_PASSWORD=root
Relacionar productos y categorías con Eloquent
Antes de crear el listado, vamos a indicar que un producto pertenece a una categoría, dentro del modelo de productos en app/Product.php
:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model { public function category() { return $this->belongsTo(ProductCategory::class); } }
Además, indicaremos que cada categoría puede tener muchos productos en app/ProductCategory.php
:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class ProductCategory extends Model { public function product() { return $this->hasMany(Product::class); } }
Generar un listado de productos con Laravel
A continuación, vamos a generar un listado de productos utilizando una ruta y una vista. Primero declaremos la ruta en routes/web.php
:
<?php Route::get('/productos', function () { $products = \App\Product::all(); return view('products', ['products' => $products]); });
Luego creemos una plantilla de Blade en resources/views/products.blade.php
con el siguiente código:
<!doctype html> <html lang="es"> <head> <meta charset="UTF-8"> </head> <body> <ul> @foreach($products as $product) <li> <a href="{{ url('productos/'.$product->slug) }}"> <strong>{{ $product->title }}</strong> </a> - <a href="{{ url('productos/categoria/'.$product->category->slug) }}"> {{ $product->category->title }} </a> </li> @endforeach </ul> </body> </html>
Agregando estilos CSS a una aplicación de Laravel
Si quieres ver el listado con estilos de CSS e imágenes puedes descargar los siguientes archivos:
- Estilos de CSS
- Imágenes de prueba
- Archivos de Sass (opcional)
- Layout de Blade
- Plantilla de productos de Blade (actualizada)
Mira el código en GitHub: actual, resultado, comparación.
La plantilla de productos es muy similar a la presentada arriba (salvo por los cambios al HTML), el único cambio con Blade es la inclusión de la imagen:
<!-- resources/views/products.blade.php --> <img src="{{ asset("img/products/{$product->image}") }}" alt="Product image" width="300px" height="200px" class="item-image">
Nota que en la base de datos guardamos solo el nombre de la imagen y en el sistema de archivos guardamos la imagen como tal (en un proyecto real típicamente irían en el directorio storage/app/public
, yo las he colocado en public/img/products
).
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.
Lección siguiente Tip de optimización con Eloquent #1: Verifica las consultas ejecutadas