Relaciones MUCHOS a muchos Inversas o Invertidos en Laravel

Las relaciones muchos a muchos son un tipo de relación disponibles en las base de datos de tipo relacional donde múltiples registros de una tabla se relacionan con múltiples registros de otra tabla; por ejemplo, si tenemos una relación de Post y Etiquetas, en donde un Post puede tener muchas Etiquetas y una Etiqueta puede estar asignada a múltiples Posts. Esto significa que un registro puede estar asociado con muchos registros; para guardar este tipo de relación se usa una tabla pivote que almacene al menos las PKs de ambas entidades; entonces, en este tipo de relación podemos obtener las etiquetas de un post, que sería la relación directa o podemos obtener los posts de una etiqueta que sería la relación inversa.

Relaciones muchos a muchos en Laravel

En esta entrada, vamos a conocer cómo podemos trabajar con las relaciones Muchos a Muchos de tipo inversas en Laravel.

Trabajando con la mucho a mucho relación directa

Antes que eso, vamos a ver como es la conexión directa, en este ejemplo tengo una relación normalitas entre Posts y Tags o etiquetas, en donde un Post tiene múltiples etiquetas y una etiqueta puede estar asignada a uno o muchos Post, por lo tanto es una relación de muchos a muchos; para esto, tenemos una tabla pivote llamada taggable en la cual guardamos dichos valores: la misma tiene la siguiente estructura:

  • La columna de tag_id guarda los identificadores de la tabla Tag 
  • La columna de taggable_id guarda los identificadores de la tabla Post

Si vamos a mantener una relación en la cual una etiqueta PERTENECE a un Post, tenemos:

class Post extends Model
{
    protected $fillable = ...
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }

Para las etiquetas que es la relación inversa (si quieres obtener los post de una etiqueta)

class Tag extends Model
{
    protected $fillable = ...
    public function post()
    {
        return $this->hasMany(Post::class);
    }
}

Para obtener las etiquetas de un post:

$posts = Post->with('tags')->get();

Relación inversa

El problema viene, cuando quieres obtener las relaciones de manera inversa, es decir, dado una etiqueta, quieres obtener todos los Post que pertenezcan a esa etiqueta; para eso, desde la etiqueta, tenemos que crear la relación directa, ya que con el hasMany NO podemos hacer esta operacion; asi que:

 public function myPosts()
    {
        return $this->belongsToMany(Post::class,'taggables','tag_id','taggable_id');
    }

Quedando como:

class Tag extends Model
{
    protected $fillable = ['title', 'url_clean'];
    public function post()
    {
        return $this->hasMany(Post::class);
    }
    public function myPosts()
    {
        return $this->belongsToMany(Post::class,'taggables','tag_id','taggable_id');
    }
}

Y con esto ya podemos obtener la relación directa entre Tags/Etiquetas y Posts; así que:

$posts = $tag::myPost()->get();

En mi caso, tengo una relación más, que es la de cursos, en la cual un post pertenecen a un curso, así que:

    $courses_tags = Tag::whereHas('myPost', function ($query) {
                return $query->where('type', 'courses');
            })->get();

Y la relación o modelo para nuestro curso es:

class Course extends Model
{
    protected $fillable = ['name', 'description', 'image', 'post_id'];
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}
class Post extends Model
{
    protected $fillable = ['title', 'url_clean', 'content', 'category_id', 'posted', 'description', 'final_content', 'aux_content', 'web_content', 'image', 'path', 'date', 'type'];
    public function category()
    {
        return $this->belongsTo(Category::class);
    }
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

Otro ejemplo de relaciones de tipo muchos a muchos primero, se puede crear una tabla intermedia llamada "product_tag" que tenga las claves foráneas para el producto y la etiqueta, es decir, esta sería la tabla pivote. Ahora, se pueden definir los modelos de Eloquent de Laravel y sus correspondientes relaciones entre ellos. 

El modelo de producto, se usar el método belongsToMany() para definir la relación con la etiqueta, en donde un post tiene múltiples etiquetas

Mientras que en el modelo de etiqueta se puede usar el mismo método para definir la relación inversa con los productos:

class Product extends Model
{
   public function tags()
   {
       return $this->belongsToMany(Tag::class);
   }
}
class Tag extends Model
{
   public function products()
   {
       return $this->belongsToMany(Product::class);
   }
}

Para referenciarlas tenemos:

$product = Product::find(1);
$tags = $product->tags;

$tag = Tag::find(1);
$products = $tag->products;

- Andrés Cruz

In english
Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz En Udemy

Acepto recibir anuncios de interes sobre este Blog.