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

Laravel Schema Macros Laravel Package

envor/laravel-schema-macros

A Laravel package that extends the Schema/Blueprint builder with handy macros for defining common database table columns and constraints, reducing boilerplate in migrations and keeping schema definitions concise.

View on GitHub
Deep Wiki
Context7

Getting Started

envor/laravel-schema-macros adds reusable macros to Laravel's schema builder so you can stop copy‑pasting the same column definitions (and, as of v1.1.6, stop hand‑writing table‑clone DDL) across migrations.

Minimal setup:

composer require envor/laravel-schema-macros

The service provider is auto‑discovered. Macros are registered onto Illuminate\Database\Schema\Blueprint (and Schema) at boot, so they are available in every migration, seeder, and test without extra wiring.

Where to look first:

  1. vendor/envor/laravel-schema-macros/src/ — the provider lists exactly which macros exist and whether any are config‑gated. This is the fastest way to get an accurate macro inventory instead of relying on the README.
  2. vendor/envor/laravel-schema-macros/tests/ — the test suite is the de facto usage documentation; it shows real call signatures and driver assumptions.
  3. config/schema-macros.php — only if php artisan vendor:publish exposes one; check the provider's mergeConfigFrom call.

First use case — the new copy macro (added in v1.1.6), which is the headline feature of this release:

// cloning a reference table for a feature branch or a test fixture
Schema::copy('templates', 'templates_scratch');

and the more common day‑to‑day case, a repeatable column set:

// AppServiceProvider::boot()
Blueprint::macro('auditColumns', function () {
    $this->timestamp('created_at')->nullable();
    $this->timestamp('updated_at')->nullable();
    $this->unsignedBigInteger('created_by')->nullable();
});

// migration
Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->auditColumns();
});

Implementation Patterns

Register project macros in the same place. Keep package macros and your own in AppServiceProvider::boot() (or a dedicated SchemaMacroServiceProvider) so the ordering is explicit and greppable. A macro that calls another macro only works if the callee was registered first.

Compose, don't nest closures. Parameterise macros with flags rather than branching inside the migration:

Blueprint::macro('softDeletesWithUser', function (bool $withUser = true) {
    $this->softDeletes();
    if ($withUser) {
        $this->foreignId('deleted_by')->nullable();
    }
});

Use copy for fixtures, not for application schema. The natural workflow is test/CI setup and local scratch tables:

protected function setUp(): void
{
    parent::setUp();
    Schema::dropIfExists('orders_scratch');
    Schema::copy('orders', 'orders_scratch');
}

Wrap it in Schema::hasTable() guards so a partially migrated test database doesn't blow up.

Feature‑branch / preview environments. Cloning a small reference table (countries, plans, templates) into a namespace‑suffixed copy is a clean pattern; do the drop in the migration's down() and gate the whole thing behind app()->environment('local', 'testing').

Seeding. Where a seeder needs a pristine snapshot of a table to compare against, copy before mutating is cheaper and more readable than a transaction + rollback dance.

Keep macros declarative. If a macro grows a config lookup, an environment check, and three conditionals, promote it to a custom Blueprint subclass or an explicit migration helper class. Macros are global and untyped — they're a convenience layer, not an abstraction layer.

Integration with tooling. Macros are invisible to static analysis and to php artisan schema:dump output. If you rely on squashed schema dumps, make sure the dump is generated from a database that was migrated, not from a diff of macro calls.

Gotchas and Tips

Macros are process‑global and static. Registration happens once per boot; tests that use RefreshDatabase inherit whatever was registered in the first booted provider. If a macro "works in tinker but not in the test suite," the provider almost certainly didn't run in that context (e.g. a custom test case that bypasses the app bootstrapping).

copy is driver‑dependent DDL. Depending on the implementation and your connection, a table clone may or may not carry indexes, foreign keys, triggers, auto‑increment state, or defaults. Verify explicitly on MySQL/MariaDB, Postgres, and SQLite before shipping it into a migration that runs anywhere other than local/CI. Run SHOW CREATE TABLE on both sides the first time you use it.

Cross‑connection copies. Schema statements execute against the connection in use, not against the model's connection. Set Schema::connection('...') explicitly, and don't assume copy can bridge two different databases on one server — most drivers can't, and the failure mode is a silent empty table rather than an exception.

Transactions. PostgreSQL supports transactional DDL, MySQL does not. A migration that creates, copies, and then fails will leave an orphan table on MySQL. Make copy steps idempotent (dropIfExists first) so a re‑run is safe.

Down migrations. There's no automatic inverse for a copied table. Always write the matching Schema::dropIfExists(...) in down().

Naming collisions. A macro name that later appears as a first‑party Blueprint method will shadow or be shadowed depending on registration order. Prefix project macros (auditColumns, not timestamps) and check Blueprint::hasMacro('name') before registering in a defensive provider.

Debugging. Two quick probes:

Blueprint::hasMacro('auditColumns');   // registration happened?
Schema::getFacadeRoot()->getConnection()->getDriverName(); // which driver am I actually on?

If a macro throws Call to undefined method, the receiver is wrong — $this inside a Blueprint macro is the blueprint, not the schema builder, and the two macro registries are separate.

IDE and static analysis. PhpStorm and Larastan won't know about macro methods. Add a _ide_helpers.php stub or a @method annotation block; otherwise every macro call is a red squiggle and a suppression comment.

Version pinning. v1.1.6 is additive — a new copy macro plus a Dependabot bump of fetch-metadata (CI‑only, no runtime impact). No breaking changes, no deprecations, no config changes, so an upgrade from v1.1.5 is safe. Pin to ^1.1 and let the minor bumps flow; nothing here warrants a stricter constraint.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route