Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Meta Model Laravel Package

laragear/meta-model

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require laragear/meta-model
    

    Publish the config (if needed) with:

    php artisan vendor:publish --provider="Laragear\MetaModel\MetaModelServiceProvider"
    
  2. Extend Your Model: Add the HasCustomization trait to your package model:

    use Laragear\MetaModel\HasCustomization;
    
    class MyPackageModel extends Model
    {
        use HasCustomization;
    }
    
  3. Define Base Migration: Override migration() to return a CustomMigration instance:

    protected static function migration(): string
    {
        return CustomMigration::make(function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->timestamps();
        });
    }
    
  4. First Use Case: Let third-party developers customize your model by publishing their own migrations or model extensions in a config/metamodel.php file:

    return [
        'models' => [
            'Vendor\Package\Models\MyPackageModel' => [
                'customizations' => [
                    'add_column' => [
                        'type' => 'migration',
                        'data' => [
                            'column' => 'custom_field',
                            'type' => 'text',
                        ],
                    ],
                ],
            ],
        ],
    ];
    

Implementation Patterns

Workflow for Package Developers

  1. Define Base Schema: Use CustomMigration::make() to encapsulate your default schema logic. This ensures customizations are applied after your base schema.

  2. Expose Customization Hooks: Provide clear documentation for developers on how to extend your model via metamodel.php. Example:

    // In your package's docs:
    // To add a custom field to MyPackageModel:
    // config/metamodel.php
    // 'customizations' => [
    //     'add_column' => [
    //         'type' => 'migration',
    //         'data' => ['column' => 'slug', 'type' => 'string'],
    //     ],
    // ]
    
  3. Dynamic Migration Generation: Override getCustomMigration() in your model to merge base and custom migrations:

    public function getCustomMigration()
    {
        return CustomMigration::make(function (Blueprint $table) {
            // Base schema
            $table->id();
            $table->string('title');
        })
        ->mergeCustomizations();
    }
    
  4. Validation Layer: Add validation in boot() to ensure customizations are safe:

    protected static function boot()
    {
        parent::boot();
        if (static::hasCustomizations()) {
            static::validateCustomizations();
        }
    }
    

Workflow for End Users

  1. Extend Models: Publish customizations in config/metamodel.php:

    return [
        'models' => [
            'Vendor\Package\Models\MyPackageModel' => [
                'customizations' => [
                    'scopes' => [
                        'active' => \Vendor\Package\Scopes\ActiveScope::class,
                    ],
                    'mutators' => [
                        'title' => function ($value) {
                            return strtoupper($value);
                        },
                    ],
                ],
            ],
        ],
    ];
    
  2. Run Migrations: Use the metamodel:migrate Artisan command to apply customizations:

    php artisan metamodel:migrate
    
  3. Override Defaults: Use mergeCustomizations() to override or extend existing behavior:

    // Override a column type
    CustomMigration::make(function (Blueprint $table) {
        $table->string('title', 255); // Default
    })
    ->mergeCustomizations(['title' => 'text']);
    

Gotchas and Tips

Pitfalls

  1. Migration Order: Custom migrations run after your base schema. Ensure your base schema includes all required columns (e.g., id()) before customizations are applied.

  2. Schema Conflicts: Customizations may introduce schema conflicts (e.g., duplicate columns). Validate customizations in boot():

    public static function validateCustomizations()
    {
        $customizations = config("metamodel.models." . static::class);
        if (isset($customizations['customizations']['add_column'])) {
            foreach ($customizations['customizations']['add_column'] as $column) {
                if (static::hasColumn($column['column'])) {
                    throw new \RuntimeException("Column {$column['column']} already exists.");
                }
            }
        }
    }
    
  3. Caching Issues: Clear configuration cache after adding customizations:

    php artisan config:clear
    
  4. Octane Compatibility: If using Laravel Octane, ensure migrations are run in the correct queue to avoid race conditions during hot reloads.

Debugging Tips

  1. Log Customizations: Add debug logging to metamodel.php:

    'debug' => [
        'log_customizations' => true,
    ],
    

    This will log all applied customizations to storage/logs/laravel.log.

  2. Inspect Migrations: Use php artisan metamodel:inspect to preview pending customizations before migration.

  3. Rollback Customizations: To revert customizations, manually rollback migrations or use a metamodel:rollback command (if implemented):

    php artisan metamodel:rollback --model=Vendor\Package\Models\MyPackageModel
    

Extension Points

  1. Custom Migration Types: Extend Laragear\MetaModel\CustomMigration to support additional customization types (e.g., add_index, add_foreign):

    class ExtendedCustomMigration extends CustomMigration
    {
        public function addForeign(string $column, string $table, string $foreignColumn)
        {
            $this->customizations['foreign'][] = compact('column', 'table', 'foreignColumn');
        }
    }
    
  2. Dynamic Model Events: Use registerCustomEvents() to dynamically bind events based on customizations:

    protected static function registerCustomEvents()
    {
        if (static::hasCustomization('observers')) {
            static::observe(config("metamodel.models." . static::class . ".observers"));
        }
    }
    
  3. Package-Specific Config: Allow users to override default customization paths via config:

    // config/metamodel.php
    'paths' => [
        'customizations' => database_path('customizations'),
    ],
    
  4. Testing Customizations: Use Laravel’s RefreshDatabase trait to test customizations in isolation:

    use Illuminate\Foundation\Testing\RefreshDatabase;
    
    class MyPackageModelTest extends TestCase
    {
        use RefreshDatabase;
    
        public function test_customizations()
        {
            config(['metamodel.models.Vendor\Package\Models\MyPackageModel.customizations' => [...]]);
            $this->artisan('metamodel:migrate')
                 ->expectsOutput('Migration applied successfully.')
                 ->assertExitCode(0);
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc