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
