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

Schema Analyzer Laravel Package

mouf/schema-analyzer

A PHP package from the Mouf framework that analyzes database schemas, introspecting tables and columns to help map or generate PHP classes from an existing database structure. Useful for reverse-engineering models and keeping code in sync with your schema.

View on GitHub
Deep Wiki
Context7

Getting Started

There is no Laravel service provider here — this is a plain PHP utility library that sits on top of Doctrine DBAL's SchemaManager. Treat it as a CLI/one-off introspection tool rather than a runtime dependency.

Install and wire up a DBAL connection

composer require mouf/schema-analyzer doctrine/dbal

Laravel 10 and earlier still exposes a Doctrine connection:

$dbal = DB::connection()->getDoctrineConnection();

Laravel 11+ removed getDoctrineConnection() along with the hard doctrine/dbal requirement, so build the connection yourself from the Laravel config:

use Doctrine\DBAL\DriverManager;

$config = config('database.connections.mysql');

$dbal = DriverManager::getConnection([
    'driver'   => 'pdo_mysql',                    // map from $config['driver']
    'host'     => $config['host'],
    'port'     => $config['port'],
    'dbname'   => $config['database'],
    'user'     => $config['username'],
    'password' => $config['password'],
    'charset'  => $config['charset'] ?? 'utf8mb4',
]);

Where to look first. The README is thin for a package this small (8 stars, 0 dependents), so read src/ directly. Skim for the top-level analyzer class, then confirm the method signatures with php -r or a throwaway tinker session before building anything on them. Because the class names aren't something you should assume from memory, do a grep -r "function " src/ and note what's public.

First use case. Point it at a legacy database you're about to migrate into Laravel migrations, and dump every table, column, index, and foreign key to the console. That gives you a checklist to write Schema::create() calls against, without guessing at column types or FK names.

$analyzer = new SchemaAnalyzer($dbal); // confirm exact class name in src/

foreach ($analyzer->getTables() as $table) {
    $this->line($table->getName());
    foreach ($table->getColumns() as $column) {
        $this->line("  {$column->getName()} {$column->getType()->getName()}");
    }
}

Implementation Patterns

Snapshot-and-diff Artisan command. The highest-leverage pattern. Serialize the analyzed schema to JSON and commit it. A later run diffs the live schema against the committed snapshot to catch drift between what migrations say and what the database actually has.

class SnapshotSchema extends Command
{
    protected $signature = 'schema:snapshot {--connection=mysql}';

    public function handle()
    {
        $snapshot = collect($this->analyzer()->getTables())
            ->mapWithKeys(fn ($t) => [
                $t->getName() => [
                    'columns' => collect($t->getColumns())->map->getName()->all(),
                    'indexes' => collect($t->getIndexes())->map->getName()->all(),
                    'fks'     => collect($t->getForeignKeys())->map->getName()->all(),
                ],
            ])
            ->sortKeys()
            ->all();

        file_put_contents(
            database_path('schema-snapshot.json'),
            json_encode($snapshot, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
        );
    }
}

CI drift check. Run schema:snapshot in CI against a database built purely from php artisan migrate:fresh, then git diff --exit-code database/schema-snapshot.json. This fails the build when someone hand-edits a database or forgets to commit a migration. It is a cheap, high-signal guard that Laravel's own tooling does not give you out of the box.

Bind it as a singleton. Don't instantiate per call — the analyzer does real round-trips against information_schema and will be slow if rebuilt repeatedly.

$this->app->singleton(SchemaAnalyzer::class, function ($app) {
    return new SchemaAnalyzer($app->make('db.dbal'));
});

Legacy introspection → migration scaffolding. Walk tables in dependency order (FK-free tables first), emit Schema::create() stubs, and let a human fix types. Do not auto-run generated migrations — the type mapping is lossy (see Gotchas).

Pre-deploy schema assertion. A tiny artisan deploy:check-schema that asserts required tables/columns exist before a rolling deploy kicks off. Cheaper than a failed request at 3am.

Documentation and onboarding. Feed the output into a markdown table or generate Mermaid erDiagram blocks from the foreign keys. Since this package is DBAL-native, the FK graph is already there — you're just formatting it.

Gotchas and Tips

Version pinning is not optional. With 0 dependents and 8 stars, there is no ecosystem pressure testing upgrades. Pin to a known-good tag in composer.json and read the changelog before bumping. Be prepared to fork — it's a small enough codebase that patching locally is realistic.

DBAL introspection types ≠ Laravel column types. MySQL tinyint(1) may surface as a small integer, enum as a string, Postgres jsonb and arrays as their own DBAL types. Never feed analyzer output straight into Schema::create() without a translation map for every type your app uses.

Case sensitivity bites cross-platform. Postgres folds unquoted identifiers to lowercase; MySQL's behavior depends on lower_case_table_names. Snapshot diffs between a Mac dev box and a Linux CI runner will show phantom changes if you compare raw strings. Normalize with strtolower() before diffing.

Foreign keys and indexes need privileges. On restricted MySQL/Postgres users, information_schema returns partial or empty results rather than an error. If FK lists come back empty on one environment but populated on another, check grants before assuming a schema problem.

Point it at a replica. Introspection queries against information_schema on a large schema can be surprisingly expensive, and on MySQL can take metadata locks. Never run the snapshot command against a production primary during peak traffic.

Laravel 11+ connection plumbing. The missing getDoctrineConnection() is the number one trip-up. Keep one small DbalConnectionFactory helper and reuse it everywhere — don't scatter DriverManager::getConnection() calls with slightly different config arrays.

Extension point that always works. If the analyzer lacks a method you need, drop down to $dbal->createSchemaManager() and call listTableDetails(), introspectTable(), or listTables() directly. The package is a convenience layer, not a walled garden — mixing both is fine and often clearer than hacking the package.

Don't use it in the hot request path. This is deploy/CLI/CI tooling. Caching its output in Redis to serve live requests is a smell; Laravel's own Schema::getColumns() / Schema::getTables() (Laravel 10.30+) are lighter and framework-native for runtime checks.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource