Skip to content

Conversation

ayzerobug
Copy link

Morph Conversion Methods

Laravel now provides convenient methods to convert existing foreign key columns to polymorphic relationships. This is particularly useful when you need to change a single foreign key relationship to support multiple model types.

Available Methods

  • foreignIdToMorph($column, $morphName, $defaultOwnerType) - Converts to integer-based morph
  • foreignIdToUuidMorph($column, $morphName, $defaultOwnerType) - Converts to UUID-based morph
  • foreignIdToUlidMorph($column, $morphName, $defaultOwnerType) - Converts to ULID-based morph

Usage

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('posts', function (Blueprint $table) {
    // Convert user_id foreign key to polymorphic author relationship
    $table->foreignIdToMorph('user_id', 'author', 'App\Models\User');
    
    // Convert to UUID-based morph
    $table->foreignIdToUuidMorph('user_id', 'author', 'App\Models\User');
    
    // Convert to ULID-based morph
    $table->foreignIdToUlidMorph('user_id', 'author', 'App\Models\User');
});

What It Does

Each method performs the following operations:

  1. Drops the existing foreign key constraint
  2. Renames the column from {column} to {morphName}_id
  3. Changes the column type to the appropriate type (bigint, uuid, char(26))
  4. Adds the morph type column as {morphName}_type
  5. Creates a composite index on both columns for performance
  6. Updates existing records with the provided default owner type

Example Migration

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            // Convert user_id to polymorphic author relationship
            $table->foreignIdToMorph('user_id', 'author', 'App\Models\User');
        });
    }

    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropMorphs('author');
            $table->foreignId('user_id')->constrained();
        });
    }
};

Database Support

These methods work with all supported Laravel database drivers:

  • MySQL
  • PostgreSQL
  • SQLite
  • SQL Server

Generated SQL Example

For $table->foreignIdToMorph('user_id', 'author', 'App\Models\User'):

-- Drop existing foreign key
ALTER TABLE `posts` DROP FOREIGN KEY `posts_user_id_foreign`;

-- Rename column
ALTER TABLE `posts` RENAME COLUMN `user_id` TO `author_id`;

-- Change column type
ALTER TABLE `posts` MODIFY `author_id` BIGINT UNSIGNED NOT NULL;

-- Add morph type column
ALTER TABLE `posts` ADD `author_type` VARCHAR(255) NULL AFTER `author_id`;

-- Add composite index
ALTER TABLE `posts` ADD INDEX `posts_author_type_author_id_index`(`author_type`, `author_id`);

-- Update existing records
UPDATE `posts` SET `author_type` = 'App\\Models\\User' WHERE `author_id` IS NOT NULL AND `author_type` IS NULL;

Use Cases

  • Converting single foreign keys to polymorphic relationships
  • Adding support for multiple model types to existing relationships
  • Migrating from specific foreign keys to flexible morph relationships
  • Supporting different ID types (integer, UUID, ULID) in morph relationships

Notes

  • The original column data is preserved during conversion
  • Existing foreign key constraints are automatically removed
  • A composite index is created for optimal query performance
  • All existing records are updated with the provided default owner type

@taylorotwell
Copy link
Member

Thanks for your pull request to Laravel!

Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include.

If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants