Suppose user has many photos and post also has many photos.
Hence instead of making two separate tables like photo_users or photo_posts we can write photos table only to associate/accommodate rows of photos for both users and posts table.
That is if Photo is a child model then User and Post are parent model and both User and Post model has single association to Photo model instead of separate association.
This type of relationship is known as polymorphic relationship and photos table is polymorphic table in following way.
photos ( child table )
- id
- photoable_id
- photoable_type
- filename
- timestamps
users ( parent table )
- id
- name
- email
- password
- timestamps
posts ( parent table )
- id
- title
- timestamps
Now the process for code setup of this type relationship is mentioned below step by step
Step 01: Migration setup for photos table will be like below
public function up() { Schema::create('photos', function (Blueprint $table) { $table->id(); $table->integer('photoable_id')->unsigned(); $table->string('photoable_type'); $table->string('filename'); $table->timestamps(); }); }
Step 02: Model setup for Photo will be like below
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Photo extends Model { use HasFactory; protected $fillable = ['photoable_id', 'photoable_type', 'filename']; public function photoable() { return $this->morphTo(); } }
Step 03: Model setup for Post will be like below. We need to have posts migration for creating tables in the database also. We can use artisan command like below for this php artisan make:migration create_posts_table
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Post extends Model { use HasFactory; protected $fillable = ['title']; public function photos() { return $this->morphMany(Photo::class, 'photoable'); } }
Step 04: Model class for User will be like below
class User extends Authenticatable { public function photos() { return $this->morphMany(Photo::class, 'photoable'); } }
Step 05: In PostController.php creating, updating, displaying and deleting rows from this relationship
function create() { // $images = ['1.jpg', '2.jpg', '3.jpg']; $post = Post::create(['title' => 'test title']); foreach( $images as $image ) { $post->photos()->create(['filename' => $image]); } return redirect()->route('posts.index'); } function index() { $posts = Post::with('photos')->get(); dd($posts); } function edit(Post $post) { // $post->load('photos'); $post->update(['title' => 'test title 2']); $count = 1; foreach( $post->photos as $photo ) { $photo->update([ 'filename' => $count.'.png' ]); $count++; } return redirect()->route('posts.index'); } function delete(Post $post) { $post->load('photos'); //dd($post); $post->photos->each->delete(); $post->delete(); return redirect()->route('posts.index'); }
Step 06: In routes/web.php we need to setup route of PostController
Route::resource('posts', PostController::class); Route::get('/posts/delete/{post}', [PostController::class, 'delete']);
Now, This is now done for PostController and we need to do the steps 5 ( creating, listing, updating and deleting ) and 6 ( routing ) like above for UserController.
Only difference will be in step 05 which will be like below ( only create() method is shown )
function create() { // $images = ['1.jpg', '2.jpg', '3.jpg']; $data = ['name' => 'Md mahfoozur Rahman', 'email' => 'mahfoozur.rahman.bd@gmail.com', 'password' => bcrypt('password')]; $user = User::create($data); foreach( $images as $image ) { $user->photos()->create(['filename'=>$image]); } return redirect()->route('users.index'); }
For the sake of simplicity in create() method we have used dummy image names in array instead of using actual multiple file uploads for both user and post .
In real production development these array will be populated from submission of form with multiple image files.