domingo, 23 de marzo de 2025

Top 5 de la semana

Artículos relacionados

Guía de Laravel 12 con caso de uso de ejemplo

Aunque han pasado unos días desde que en febrero se lanzase Laravel 12 (tal como anunciamos en nuestro anterior post), hemos querido dar un repaso un tanto especial a las novedades que ésta nueva versión nos presenta. Para ello, además de mostraros las novedades que trae consigo la nueva versión, os presentamos un caso de uso realista en el que hemos aplicado las nuevas funcionalidades y hemos tratado de explicarlas un poco.

Novedades principales de Laravel 12

Laravel 12 presenta principalmente mejoras incrementales:

  • Uso de UUID v7 como identificadores únicos ordenados cronológicamente.
  • Nuevo método del Query Builder nestedWhere() para simplificar consultas complejas.
  • Mejoras en la validación de archivos, especialmente imágenes SVG (restringidas por defecto).
  • Ejecución paralela mejorada con Concurrency::run() manteniendo claves asociativas.
  • Método mejorado para colecciones: range() con pasos variables.
  • Starter Kits renovados con autenticación avanzada incluida.

Caso de uso: Aplicación «Gestor de Tareas»

Instalación del proyecto

composer create-project laravel/laravel:^12.0 gestor-tareas
npm install && npm run dev
php artisan migrate
php artisan storage:link

Migración para tareas

// database/migrations/create_tasks_table.php
public function up() {
    Schema::create('tasks', function (Blueprint $table) {
        $table->uuid('id')->primary(); // UUID v7 por defecto en Laravel 12
        $table->foreignId('user_id')->constrained()->cascadeOnDelete();
        $table->string('titulo');
        $table->text('descripcion')->nullable();
        $table->string('imagen_path')->nullable();
        $table->timestamps();
    });
}

Explicación:
El campo id utiliza UUID v7 automáticamente gracias al trait HasUuids.

Modelo Task

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Concerns\HasUuids;

class Task extends Model {
    use HasUuids;

    protected $fillable = ['titulo', 'descripcion', 'imagen_path', 'user_id'];

    public function user() {
        return $this->belongsTo(User::class);
    }
}

Explicación:
El trait HasUuids asegura que cada tarea creada tenga automáticamente un UUID v7.

Controlador de tareas

class TaskController extends Controller {
    public function __construct() {
        $this->middleware('auth');
    }

    public function index() {
        $tareas = Task::where('user_id', auth()->id())->latest()->get();
        return view('tasks.index', compact('tareas'));
    }

    public function store(Request $request) {
        $request->validate([
            'titulo' => 'required|string|max:255',
            'descripcion'=> 'nullable|string',
            'imagen'=> ['nullable', File::image()] // No permite SVG por defecto
        ]);

        $request->mergeIfMissing(['descripcion' => '']);

        $datos = $request->only(['titulo', 'descripcion']);
        if ($request->hasFile('imagen')) {
            $datos['imagen_path'] = $request->file('imagen')->store('imagenes', 'public');
        }

        $datos['user_id'] = Auth::id();

        Task::create($datos);

        return redirect()->route('tasks.index')->with('success', 'Tarea creada.');
    }
}

Explicación:
Demuestra validación avanzada (sin SVG), asignación automática del usuario autenticado y el uso del método mergeIfMissing.

Uso del método nestedWhere()

Ejemplo para filtrar tareas que cumplen múltiples condiciones fácilmente:

$tareasImportantes = Task::nestedWhere(
    'prioridad', '=', 'alta', 'or', 'fecha_limite', '<', now()->addDays(7)
)->get();

Explicación:
Este método facilita hacer consultas complejas más legibles.

Comando para ejecutar tareas concurrentes

class ComputeStats extends Command {
    protected $signature = 'compute:stats';

    public function handle() {
        $resultados = Concurrency::run([
            'conteo_tareas' => fn() => DB::table('tasks')->count(),
            'calculo_matematico' => fn() => array_sum(range(1, 1000000)),
        ]);

        foreach ($resultados as $clave => $valor) {
            $this->info("{$clave}: {$valor}");
        }
    }
}

Explicación:
Ejecuta dos procesos simultáneos y muestra cómo Laravel 12 preserva las claves definidas originalmente.

Ejemplo del nuevo método range() en colecciones

$numeros = Collection::range(1, 10, 2)->all(); // [1,3,5,7,9]

Explicación:
El método range() ahora permite generar rangos con saltos especificados.

Ejemplo de prueba unitaria usando Pest PHP v3

use App\Models\Task;
use App\Models\User;

test('crear tarea genera UUID v7', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post('/tasks', ['titulo' => 'Ejemplo']);
    $tarea = Task::first();

    expect($tarea->id)->toBeUuid();
});

Explicación:
Esta prueba verifica que el modelo genera correctamente un UUID v7 al crear nuevas tareas.


Cómo ejecutar el proyecto localmente:

  • Instala dependencias PHP y JavaScript:
composer install
npm install && npm run dev
  • Ejecuta migraciones y vincula almacenamiento:
php artisan migrate
php artisan storage:link
  • Inicia servidor:
php artisan serve
  • Ejecuta el comando concurrente desde consola:
php artisan compute:stats

Hasta aquí llega nuestro ejemplo. Esperamos que al probarlo en vuestras máquinas o dockers hayáis podido ver de cerca las novedades y que lo hayáis pasado bien con la guía de hoy.

Os espero en próximos artículos!

Jordi Morillo
Jordi Morillohttps://www.programador-web.com
Soy un programador PHP Senior con más de 20 años de experiencia en desarrollo web y administración de sistemas Linux, especializado en Symfony y metodologías ágiles como Scrum. He trabajado con tecnologías como MySQL, MongoDB y WordPress, y siempre busco nuevas oportunidades para seguir aprendiendo y aplicando mis conocimientos.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!
Por favor ingrese su nombre aquí

Artículos populares