digitaldream/dbreader
digitaldream/dbreader is a Laravel package for reading existing database schemas. Inspect tables, columns, and relationships to document legacy databases or bootstrap models and migrations from an existing SQL structure. Useful when adopting Laravel in projects with established databases.
digitaldream/dbreader is a small, unmaintained (last release September 2017) Laravel package for reading database structure and/or data from an existing connection — the classic use case being introspecting a legacy or externally-owned database rather than one your app manages with migrations.
Minimal steps:
composer require digitaldream/dbreader. Because the package has no Laravel 6+ / PHP 8 support declared, expect to run composer require digitaldream/dbreader --ignore-platform-reqs on modern Laravel, or be prepared to fork it. Test on a throwaway branch first.vendor/digitaldream/dbreader/ immediately after install — that directory is the documentation. Check composer.json for the extra.laravel.providers entry, then read the service provider to see what it binds and whether it publishes a config file.php artisan vendor:publish --provider="DigitalDream\\DbReader\\DbReaderServiceProvider". If no config is published, configure the connection in config/database.php and pass the connection name explicitly.src/ for the reader class (likely something like DbReader, a facade, or an artisan command). Register the facade alias if the package's extra.laravel.aliases block defines one; older packages often rely on config/app.php.// config/database.php — dedicated, read-only credentials
'legacy' => [
'driver' => 'mysql',
'host' => env('LEGACY_DB_HOST'),
'database' => env('LEGACY_DB_DATABASE'),
'username' => env('LEGACY_DB_USERNAME'),
'password' => env('LEGACY_DB_PASSWORD'),
'charset' => 'utf8mb4',
'collation'=> 'utf8mb4_unicode_ci',
],
Treat the package as a schema introspection helper, not a query builder. The patterns that hold up in day-to-day work:
Introspect, then generate. The highest-value workflow for a package like this is reading a legacy schema and emitting Laravel artifacts. Walk the reader's table/column output and generate models, casts, and $fillable arrays:
foreach ($reader->tables('legacy') as $table) {
$columns = $reader->columns('legacy', $table); // name, type, nullable, default, key
$stub = view('stubs.model', [
'class' => Str::studly(Str::singular($table)),
'table' => $table,
'columns' => $columns,
]);
File::put(app_path("Models/{$class}.php"), $stub);
}
Commit the generated models and then delete the dependency. This is the single most defensible way to use an abandoned package: run it once, keep the output.
Read-only reporting layer. For operational dashboards against a database you don't own, wrap the reader in a repository class and inject the connection name from config so the package never appears in your domain code:
final class LegacyReports
{
public function __construct(private DbReader $reader) {}
public function tableSummaries(): array
{
return collect($this->reader->tables('legacy'))
->mapWithKeys(fn ($t) => [$t => count($this->reader->columns('legacy', $t))])
->all();
}
}
Console command for ad-hoc inspection. Wrap it in an artisan command (db:inspect {table?}) so schema questions are answered from the terminal instead of a GUI client. Cache the output with Cache::remember('schema:legacy', 3600, ...) — schema rarely changes and introspection is chatty.
Integration tip: register a second, read-only database user at the infrastructure level, not just in code. If the package ever issues an unexpected statement, the grant layer is your real safety net.
Testing: never point it at a shared database. Add a SQLite or Docker MySQL fixture in CI and assert the reader returns the expected table list, so a Laravel upgrade that breaks the package fails loudly.
each() removal, dynamic property deprecation, or ReflectionParameter::getClass() deprecation. If install or boot fails, run composer why-not and check the source for these before debugging your own code.php artisan tinker and attempting to resolve the reader class from the container. If it throws BindingResolutionException, the provider isn't loaded — add it manually to config/app.php under providers.default connection rather than the one you passed. Always pass the connection name explicitly on every call, and add a guard: refuse to run introspection against the default connection in production.information_schema lookups across hundreds of tables can take seconds. Batch by schema, cache results, and avoid calling the reader inside loops or Blade views.$this->app->extend() it or bind your own implementation behind an interface. Prefer wrapping it (adapter pattern) over subclassing, so removal later is a one-file change.DB::listen() won't necessarily catch statements issued on a separate PDO handle if the package creates its own connection. If logging looks empty, enable the general query log on the database side instead.Schema::getTables(), Schema::getColumns(), and Doctrine DBAL cover the same ground with maintained support — the right answer for most teams is to port the one or two methods you actually use and drop the dependency entirely.How can I help you explore Laravel packages today?