Saltar al contenido

Laravel Has Many Through es un tipo de relación que nos permite acceder a datos alejados de nuestro modelo.

Una relación distante en Laravel puede ser aquella entre un modelo User, Country y Posts, ¿cómo harías para obtener todos los posts de España? Este tipo de relaciones en Eloquent se conocen como Has Many Through, y sirven para tener acceso rápido y sin complejas configuraciones a modelos lejanos.

Vamos a crear un rápido ejemplo utilizando los 3 modelos comentados anteriormente, User, Country y Posts, así que crea primero las migraciones necesarias con la siguiente estructura.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCountriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('countries', function (Blueprint $table) {
            $table->id();
            $table->string("name");
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('countries');
    }
}

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->foreignId("country_id")->constrained();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId("user_id")->constrained();
            $table->string("title");
            $table->integer("points")->default(0);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

Ahora abre cada uno de sus modelos y haz las siguientes modificaciones para establecer las relaciones necesarias.

Country.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;

class Country extends Model
{
    use HasFactory;

    public function posts(): HasManyThrough {
        return $this->hasManyThrough(
            Post::class,
            User::class,
            'country_id',
            'user_id',
            'id',
            'id',
        );
    }
}

Post.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Post extends Model
{
    use HasFactory;

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

User.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    public function posts(): HasMany {
        return $this->hasMany(Post::class);
    }

    public function country(): BelongsTo {
        return $this->belongsTo(Country::class);
    }
}

Con lo anterior, ya tenemos modificados todos los modelos para que las relaciones de largo alcance Has Many Through en Laravel funcionen perfectamente, sólo nos queda utilizarlo.

<?php

use App\Models\Country;
use Illuminate\Support\Facades\Route;

Route::get('/through', function () {
    $spainPosts = Country::with(["posts:user_id,title", "posts.user:id,name,country_id"])->whereName("Spain")->first();
    dd($spainPosts->posts);
});
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