rexshijaku/sql-to-laravel-builder
Convert raw SQL queries into Laravel query builder syntax with this lightweight package. It parses SQL statements and helps translate existing queries into fluent Laravel code, making legacy SQL easier to migrate, refactor, and maintain.
Install and confirm the version you get.
composer require rexshijaku/sql-to-laravel-builder
The package is a standalone parser — no service provider is required. If you want the facade, register the alias manually in config/app.php (the package predates Laravel's auto-discovery era in parts of its docs, so don't assume it wires itself up).
Where to look first, in order:
src/ — the tokenizer/parser classes tell you exactly which SQL grammar is supported. This is the single most useful file to read before committing to the package.First use case: translate one legacy query in tinker.
use Rexshijaku\SQLToLaravelBuilder\SQLToLaravelBuilder;
$sql = "SELECT id, name FROM users WHERE active = 1 ORDER BY name ASC LIMIT 10";
$builder = new SQLToLaravelBuilder($sql); // check README for exact ctor signature
$query = $builder->toQuery(); // returns an Illuminate query builder
echo $query->toSql(); // inspect what it actually built
$query->get(); // run it against a test connection
Do this against a scratch database with a hand-built schema before you point it at anything real. The goal of the first session is not "does it work" but "does the generated SQL match the original byte-for-byte in intent."
Convert-then-paste, not convert-at-runtime. The highest-value workflow is: take a legacy .sql file, run it through the package in tinker or a throwaway route, print the generated chain with ->toSql(), then hand-edit the result into your codebase. Treat the package as a scaffolding generator, not a dependency. This sidesteps every compatibility risk in the section below.
Wrap it in a dev-only Artisan command. If you're migrating a reporting layer with dozens of queries, a command that globs database/legacy/*.sql, converts each, and dumps original / generated / bindings side by side pays for itself immediately:
foreach (glob(database_path('legacy/*.sql')) as $file) {
$sql = file_get_contents($file);
$this->line("-- {$file}");
$this->line((new SQLToLaravelBuilder($sql))->toQuery()->toSql());
}
Use it as a differential-testing oracle. For each converted query, run the original raw SQL via DB::select() and the generated builder via ->get(), then assertEquals the result sets on a seeded test database. This catches the semantic drift that syntax-level review misses — ordering, null sorting, LIKE case sensitivity.
Swap the builder for Eloquent deliberately. The generated chain targets the query builder. Once it's in your codebase, replace DB::table('users') with User::query() so scopes, soft deletes, and global constraints apply. Don't leave raw DB::table() calls behind just because the tool emitted them.
Feed it parameterless SQL. Paste queries with literal values (WHERE id = 42), not ? placeholders — the parser is happiest with complete statements. Re-introduce bindings by hand when you move the result into production code.
Keep a conversion log. For a large migration, record original SQL → generated chain → manual corrections in a markdown file. Reviewers need to see what the tool got wrong, not just what it produced.
Maintenance risk is the headline. Last release was November 2021. Laravel 9+ moved query-builder internals, and PHP 8.1+ tightened deprecations; expect friction on modern stacks. Pin the package in require-dev, never require, and budget for forking if you lean on it heavily.
SQL coverage is partial by construction. Simple SELECT/WHERE/JOIN/ORDER BY/LIMIT is the sweet spot. CTEs, window functions, UNION, correlated subqueries, CASE expressions, JSON operators, and vendor-specific syntax are where output degrades silently — you get a builder, not an error. Always diff the generated toSql() against the source.
Silent semantic drift is the real danger. Even supported constructs can shift meaning: LIMIT inside subqueries, NULL ordering defaults, LIKE escaping, implicit INNER vs LEFT joins, and identifier quoting/prefixing. A query that "converts" is not a query that "matches."
Never pass user input to the parser. This is a developer tool. If you expose it through a route or a queue job, you've built a SQL-injection surface and a CPU-burn surface at the same time — pathological input can hang the tokenizer.
Debugging: compare three things. $originalSql, $query->toSql(), and $query->getBindings(). Most confusion comes from bindings being inlined or reordered relative to what you expect. If the output looks truncated, dump the parser's token stream directly rather than guessing.
No model resolution. The tool only knows table names. Anything relying on relationships, accessors, or model scopes must be re-added by hand after conversion.
Extension points are the parser, not config. There's effectively no config file to tune — the way to extend it is to subclass the builder or fork and add grammar rules for the constructs you need. If you find yourself doing that for more than two constructs, switch to writing the builder chains manually; you'll finish sooner.
Laravel version pin. Check composer.json's illuminate/* constraints before installing. On a Laravel 10/11 app, resolve the dependency conflict by installing it in an isolated scratch project and copying output across, rather than fighting the constraint solver in your main app.
How can I help you explore Laravel packages today?