Products have photos and customers an avatar. One images table serves both by recording which kind of parent each row belongs to. In its migration, $table->morphs('imageable') creates imageable_type (VARCHAR(255)), imageable_id (BIGINT UNSIGNED) and one index on the pair. Product::images() returns $this->morphMany(Image::class, 'imageable'), Customer::avatar() returns $this->morphOne(Image::class, 'imageable'), and the inverse Image::imageable() is a bare $this->morphTo(), which takes its column names from the method name.
use App\Models\{Customer, Image, Product};
$mug = Product::firstWhere('sku', 'AC-MUG-01');
$image = $mug->images()->create(['path' => 'products/mug.jpg']);
echo "{$image->imageable_type} #{$image->imageable_id}\n";
echo Product::find(1)->images->pluck('path')->join(', '), "\n";
echo Customer::find(1)->avatar->path, "\n";
echo Image::all()->map(fn ($i) => class_basename($i->imageable).' '.$i->imageable->id), "\n";App\Models\Product #7 products/php-front.jpg, products/php-back.jpg avatars/ana.jpg ["Product 1","Product 1","Customer 1","Product 7"]
Images 1 and 3 share imageable_id 1; only the type tells them apart. MySQL 524 cannot enforce a foreign key that points at several tables, so deleting a product leaves orphan images unless a deleting event removes them, and stored class names tie data to namespaces (Polymorphic Many to Many).