pivot-table-con-eloquent-en-laravel

¡Hola a todos! quiero compartir con ustedes un ejemplo de cómo se puede relacionar tres o más tablas utilizando una tabla pivot, esta pregunta surgió en la comunidad hecha por @alexd2 y me motivó a que compartiera la respuesta en forma de tutorial para que se beneficiaran más personas. Espero que les ayude.

Supongamos que tenemos tres tablas que están relacionas directamente una con la otra y entre las tres, las cuales son: Users, Tasks, Menu.  Esta relación sería de muchos a muchos utilizando como tabla pivot menu_task_user.

Para ello, crearemos las cuatro tablas en nuestra base de datos, luego definiremos nuestros modelos o entidades, dependiendo la estructura que estemos usando en nuestro proyecto y, finalmente, agregaremos las relaciones respectivas de cada modelo o entidad.

Migraciones

Antes de realizar las migraciones recuerda crear la base de datos y sustituir en el archivo .env del proyecto, tus credenciales de acceso.

Para la tabla users, usamos la migración que viene por defecto en Laravel (create_users_table.php),  la cual contiene los siguientes campos:

$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->timestamps();

Creamos el archivo de migración para la tabla tasks:

php artisan make:migration create_tasks_table --create=tasks

agregamos los siguientes campos:

public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

Para la tabla menu creamos la migración:

php artisan make:migration create_menu_table --create=menu

En la cual, tenemos lo siguiente:

public function up()
    {
        Schema::create('menu', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('url');
            $table->timestamps();
        });
    }

Relacionaremos estas tres tablas con una tabla pivote que llamaremos menu_task_user que incluirá como llaves foráneas, los id de las tablas anteriores, más un campo para representar el status:

php artisan make:migration create_menu_task_user_table --create=menu_task_user
 public function up()
    {
        Schema::create('menu', function (Blueprint $table) {
            $table->increments('id');
            $table->boolean('status');
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')->references('id')->on('users');
            $table->integer('task_id')->unsigned();
            $table->foreign('task_id')->references('id')->on('tasks');
            $table->integer('menu_id')->unsigned();
            $table->foreign('menu_id')->references('id')->on('menu');
            $table->timestamps();
        });
    }

y finalmente, ejecutaremos:

php artisan migrate

Creación de modelos y relaciones

Una vez teniendo ya las tablas hechas, crearemos los modelos para las tres tablas y allí agregaremos las relaciones de tipo belongsToMany (muchos a muchos) entre ellas. En este caso, se colocará en withPivot aquellos otros atributos que se quieren acceder desde la tabla pivot, pues por defecto Laravel sólo coloca las llaves de las tablas relacionadas con belongsToMany.

Para User, usamos el modelo que viene por defecto en Laravel que se encuentra en el directorio app y agregamos las relaciones con los otros dos modelos (Task y Menu):

class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
    public function tasks(){
        return $this->belongsToMany('\App\Task','menu_task_user')
            ->withPivot('menu_id','status');
    }

    public function menu(){
        return $this->belongsToMany('\App\Menu','menu_task_user')
            ->withPivot('task_id','status'); 
    }
}

Por otro lado, para  Task,  primero se crea el modelo y luego se relaciona con los otros dos modelos así:

php artisan make:model Task
class Task extends Model
{
   	public function users(){
    	return $this->belongsToMany('\App\User','menu_task_user')
     		->withPivot('menu_id','status'); 
	} 
	public function menu(){ 
		return $this->belongsToMany('\App\Menu','menu_task_user')
			->withPivot('user_id','status'); 
	}
}

Y por útimo para Menu, también se crea el modelo y se le agregan las relaciones:

php artisan make:model Menu
class Menu extends Model
{
	public function users(){
   		return $this->belongsToMany('\App\User','menu_task_user')
   			->withPivot('task_id','status');
   	}

   	public function tasks(){
    	return $this->belongsToMany('\App\Task','menu_task_user')
    		->withPivot('user_id','status');
   }
}

Acceso a los datos

Una vez ya creadas las relaciones en los modelos ya podremos tener acceso a los datos de las tres tablas de diferentes formas. A continuación les mostraré un ejemplo para acceder a los datos de las tablas desde User, y que de manera similar se podrá acceder a la información con cualquiera de las demás tablas.

$user = User::find(1);

//obteniendo los menus asociados al User
foreach ($user->menu as $menu) {
    //obteniendo los datos de un menu específico
    echo $menu->name;
    echo $menu->url;
    //obteniendo datos de la tabla pivot por menu
    echo $menu->pivot->task_id;
    echo $menu->pivot->status;
}

//obteniendo los tasks asociados al User
foreach ($user->tasks as $task) {
    //obteniendo los datos de un task específico
    echo $task->name;
    //obteniendo datos de la tabla pivot por task
    echo $task->pivot->menu_id;
    echo $task->pivot->status;
}

Para poder guardar los datos en la tabla pueden hacerlo de esta manera.

$user= User::find(1);

$user->tasks()->attach('Aquí id task',['menu_id'=>'id menu', 'status'=>true]);

Espero que este tutorial les pueda ayudar para sus proyectos; esta misma lógica se puede utilizar si fueran más de tres tablas.

Saludos a todos.

Material relacionado

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Cómo funcionan las pruebas de integración en Laravel 5.1 Lección siguiente Cómo instalar proyectos existentes de Laravel