Saltar al contenido

¿Cuántas veces has usado first() asumiendo que solo existe un registro? Si por algún error hay duplicados, first() te devolverá uno cualquiera sin avisarte. Aquí es donde sole() brilla.

Compatibilidad

  • Laravel: 8.23+

  • PHP: 7.4+

¿Qué hace sole()?

El método sole() devuelve exactamente un registro. Si no cumple esta condición, lanza una excepción:

Resultados

Comportamiento

0

ModelNotFoundException

1

Devuelve el modelo ✓

2+

MultipleRecordsFoundException

Uso básico

<?php

use App\Models\User;

// Obtener el único usuario con este email
$user = User::where('email', '[email protected]')->sole();

Compáralo con first():

<?php

// Con first(): si hay duplicados, devuelve uno cualquiera (bug silencioso)
$user = User::where('email', $email)->first();

// Con sole(): si hay duplicados, lanza excepción (detectas el problema)
$user = User::where('email', $email)->sole();

Variantes útiles

soleValue()

Cuando solo necesitas un campo específico:

<?php

// Obtener solo el nombre, garantizando un único resultado
$name = User::where('email', $email)->soleValue('name');

En colecciones

sole() también funciona en colecciones de Laravel:

<?php

$numbers = collect([1, 2, 3, 4, 5]);

// Funciona: solo hay un número mayor que 4
$result = $numbers->where(fn ($n) => $n > 4)->sole(); // 5

// Lanza excepción: hay múltiples números mayores que 2
$result = $numbers->where(fn ($n) => $n > 2)->sole(); // MultipleRecordsFoundException

Casos de uso ideales

Buscar por campos únicos

<?php

// Configuraciones del sistema donde solo debe existir una
$config = Setting::where('key', 'app_timezone')->sole();

// Registro de auditoría específico
$log = AuditLog::where('transaction_id', $transactionId)->sole();

Validar integridad en comandos

<?php

namespace App\Console\Commands;

use App\Models\User;
use Illuminate\Console\Command;

class VerifyAdminCommand extends Command
{
    protected $signature = 'verify:admin';

    public function handle(): int
    {
        try {
            $admin = User::where('role', 'super_admin')->sole();
            $this->info("Admin verificado: {$admin->email}");
            
            return self::SUCCESS;
        } catch (\Illuminate\Database\MultipleRecordsFoundException $e) {
            $this->error('Error: Existen múltiples super admins');
            
            return self::FAILURE;
        }
    }
}

En tests para asegurar datos correctos

<?php

namespace Tests\Feature;

use App\Models\Order;
use Tests\TestCase;

class OrderTest extends TestCase
{
    public function test_solo_existe_una_orden_pendiente_por_usuario(): void
    {
        $user = User::factory()->create();
        
        Order::factory()->pending()->for($user)->create();
        
        // Si el sistema permite duplicados por error, este test fallará
        $order = Order::where('user_id', $user->id)
            ->where('status', 'pending')
            ->sole();
            
        $this->assertNotNull($order);
    }
}

Manejo de excepciones

Puedes capturar las excepciones específicas:

<?php

use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\MultipleRecordsFoundException;

try {
    $user = User::where('email', $email)->sole();
} catch (ModelNotFoundException $e) {
    // No existe ningún registro
    return response()->json(['error' => 'Usuario no encontrado'], 404);
} catch (MultipleRecordsFoundException $e) {
    // Existen múltiples registros (problema de integridad)
    Log::critical('Duplicado detectado', ['email' => $email]);
    
    return response()->json(['error' => 'Error interno'], 500);
}

sole() vs first() vs firstOrFail()

Método

0 resultados

1 resultado

2+ resultados

first()

null

Modelo

Primer modelo

firstOrFail()

Excepción

Modelo

Primer modelo

sole()

Excepción

Modelo

Excepción

Usa sole() cuando la unicidad sea un requisito de negocio.

Conclusión

sole() es una herramienta defensiva. No previene duplicados, pero te avisa inmediatamente cuando existen. Úsalo en consultas donde asumes unicidad y quieres fallar rápido si esa suposición es incorrecta.

school Curso completo

Curso Laravel 12
Completo 2026

El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.

access_time 8 horas de contenido
layers 4 tecnologías en 1
update 100% actualizado
code Proyectos prácticos
Ver Curso Laravel 12 arrow_forward

star Incluido en cualquier suscripción

Rutas de aprendizaje