Laravel 9 Many To Many Polymorphic Relationship Example

https://www.laravelia.com/post/laravel-9-many-to-many-polymorphic-relationship-example

Mẫu 1.1 với model App\Models\Video

C:\xampp\htdocs\songkhoe\app\Http\Controllers\TestController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Post;
use App\Models\Video;
use App\Models\Tag;
class TestController extends Controller
{
  public function index($id)
    {
      $post = Post::find($id);
      foreach ($post->tags as $tag) {
        echo '<pre>';
        var_export($tag);
        echo '<pre>';
      }
    }
    public function index2($id)
    {
      $video = Video::find($id);
        foreach ($video->tags as $tag) {
          echo '<pre>';
          var_export($tag);
          echo '<pre>';
        }
    }
    public function index3($id)
    {
      $video = Video::find($id);
      $tag = new Tag;
      $tag->name = "laravelia.com 0";
      $video->tags()->save($tag);
    }
    public function index4($id)
    {
      $post = Post::find($id);
      $tag = new Tag;
      $tag->name = "laravelia.com 0 post";
      $post->tags()->save($tag);
    }
    public function index5($id)
    {
      //save tag for post
      $post = Post::find($id);
      $tag1 = new Tag;
      $tag1->name = "laravelia.com 1";
      $tag2 = new Tag;
      $tag2->name = "laravelia.com 2";
      $post->tags()->saveMany([$tag1, $tag2]);
    }
}php

C:\xampp\htdocs\songkhoe\routes\web.php

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TestController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/test/{id}', [TestController::class,'index']);
Route::get('/test2/{id}', [TestController::class,'index2']);
Route::get('/test3/{id}', [TestController::class,'index3']);
Route::get('/test4/{id}', [TestController::class,'index4']);
Route::get('/test5/{id}', [TestController::class,'index5']);

C:\xampp\htdocs\songkhoe\database\seeders\DatabaseSeeder.php

<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User;
use App\Models\Post;
use App\Models\Video;
use App\Models\Tag;
class DatabaseSeeder extends Seeder
{
  /**
   * Seed the application's database.
   *
   * @return void
   */
  public function run()
  {
    User::factory(10)->create();
    Post::factory(10)->create();
    Video::factory(10)->create();
    Tag::factory(10)->create();
  }
}

C:\xampp\htdocs\songkhoe\database\migrations\2022_11_21_020832_create_videos_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateVideosTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('videos', function (Blueprint $table) {
      $table->increments("id");
      $table->string('name');
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('videos');
  }
}

C:\xampp\htdocs\songkhoe\database\factories\VideoFactory.php

<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class VideoFactory extends Factory
{
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    return [
      'name' => $this->faker->text(10)
    ];
  }
}

C:\xampp\htdocs\songkhoe\app\Models\Tag.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Post;
use App\Models\Video;
class Tag extends Model
{
  use HasFactory;
  public $timestamps = false;
  protected $fillable = [
    'name'
  ];
  /**
   * Get all of the posts that are assigned this tag.
   */
  public function posts()
  {
    return $this->morphedByMany(Post::class, 'taggable');
  }
  /**
   * Get all of the videos that are assigned this tag.
   */
  public function videos()
  {
    return $this->morphedByMany(Video::class, 'taggable');
  }
}

C:\xampp\htdocs\songkhoe\database\factories\TagFactory.php

<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\Tag;
class TagFactory extends Factory
{
  protected $model = Tag::class;
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    return [
      'name' => $this->faker->text(6)
    ];
  }
}

C:\xampp\htdocs\songkhoe\database\migrations\2022_11_21_031405_create_tags_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTagsTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('tags', function (Blueprint $table) {
      $table->increments("id");
      $table->string('name');
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('tags');
  }
}

Mẫu 1.2 với model App\Models\Post

C:\xampp\htdocs\songkhoe\database\migrations\2022_11_21_020348_create_posts_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('posts', function (Blueprint $table) {
      $table->increments("id");
      $table->string('name');
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('posts');
  }
}p

Mẫu 1.3 với nhiều model App\Models\Post

Laravel many to many polymorphic relationship is a bit different from one to many polymorphic relationship. Many-to-many polymorphic relations are a bit more complicated than "morph one" and "morph many" relationships in laravel. For example, a Post model and Video model has a polymorphic relation to a Tag model.

In this tutorial, I will show you how to create polymorphic many-to-many relationships with migration with a foreign key schema for many to many relationships, use sync with a pivot table, create records, attach records, get all records, delete, update, where condition and everything related to many to many polymorphic relationship.

In this tutorial, I will create "posts", "videos", "tags" and "taggables" tables to show you an example. Each table will be connected with each other. Now we will create many to many polymorphic relationships with each other by using laravel Eloquent Model.

Many To Many (Polymorphic) Scenario

First, let's examine the table structure required to build this many to many polymorphic relationships:

posts
    id - integer
    name - string
 
videos
    id - integer
    name - string
 
tags
    id - integer
    name - string
 
taggables
    tag_id - integer
    taggable_id - integer
    taggable_type - string

PHPCopy

Model Structure of Polymorphic Relationship

Now let's define the many-to-many polymorphic relationship in our model class.

app/Models/Post.php

namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
    /**
     * Get all of the tags for the post.
     */
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

PHPCopy

Now define the relationship in the Video model like:

app/Models/Video.php

namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class Video extends Model
{
    /**
     * Get all of the tags for the post.
     */
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

PHPCopy

Now define the relationship in the Tag model like:

app/Models/Tag.php

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class Tag extends Model
{
    /**
     * Get all of the posts that are assigned this tag.
     */
    public function posts()
    {
        return $this->morphedByMany(Post::class, 'taggable');
    }
 
    /**
     * Get all of the videos that are assigned this tag.
     */
    public function videos()
    {
        return $this->morphedByMany(Video::class, 'taggable');
    }
}

PHPCopy

Retrieving The Relationship

Once our database table and models are defined, we may access the relationships via your model's dynamic relationship properties. For example, to access all of the tags for a post, you can use the tags dynamic relationship property:

App\Http\Controllers\TestController.php

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class TestController extends Controller
{
    public function index($id)
    {   
        $post = Post::find($id);
 
        foreach ($post->tags as $tag) {
            //
        }
    }
}

PHPCopy

For retrieving tags for a video:

App\Http\Controllers\TestController.php

<?php

namespace App\Http\Controllers;

use App\Models\Video;
use Illuminate\Http\Request;

class TestController extends Controller
{
    public function index($id)
    {   
        $video = Video::find($id);
 
        foreach ($video->tags as $tag) {
            //
        }
    }
}

PHPCopy

You can also retrieve the parent of a polymorphic relation from the polymorphic child model that performs the call to morphedByMany. In this case, that is the posts or videos methods on the Tag model:

<?php

use App\Models\Tag;
 
$tag = Tag::find(1);
 
foreach ($tag->posts as $post) {
    //
}
 
foreach ($tag->videos as $video) {
    //
}

PHPCopy

Recommended: Laravel One To One Polymorphic Relationship Example

Save Polymorphic Relationship Data

If we want to save or create polymorphic relationship data then we can follow the below structure:

App\Http\Controllers\TestController.php

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class TestController extends Controller
{
    public function index($id)
    {   
        $video = Video::find(1);	
 
        $tag = new Tag;
        $tag->name = "laravelia.com";
 
        $video->tags()->save($tag);


        //save tag for post
        $post = Post::find(1);	
 
        $tag1 = new Tag;
        $tag1->name = "laravelia.com";
 
        $tag2 = new Tag;
        $tag2->name = "laravelia.com 2";
 
        $post->tags()->saveMany([$tag1, $tag2]);
    }
}

PHPCopy

Recommeneded: Laravel 9 One To Many Polymorphic Relationship Example

Conclusion

I have tried to discuss the clear concept of many to many polymorphic relationships and their possible use cases in laravel applications. We should also remember that many to many polymorphic relationships are not a perfect solution to everything and should only be used when convenient or feels like the right way to go.

Last updated