Installation
composer require phpmyadmin/sql-parser
Add to composer.json if not auto-loaded:
"autoload": {
"psr-4": {
"App\\": "app/",
"PMA\\SQLParser\\": "vendor/phpmyadmin/sql-parser/src/"
}
}
Run composer dump-autoload.
First Use Case: Parsing a Query
use PMA\SQLParser\Parser;
$parser = new Parser();
$sql = "SELECT * FROM users WHERE id = 1";
$result = $parser->parse($sql);
// Outputs parsed structure (AST)
print_r($result);
Where to Look First
src/Parser.php (core logic), src/Parser/Parser.php (grammar rules).tests/ for edge cases and validation examples.Use Case: Sanitize user input or enforce SQL standards.
$parser = new Parser();
$sql = "SELECT * FROM users WHERE id = '1' OR 1=1"; // Malicious input
try {
$parser->parse($sql);
// Proceed if valid
} catch (\PMA\SQLParser\Exception $e) {
abort(400, "Invalid SQL: " . $e->getMessage());
}
Use Case: Extract metadata (tables, columns, joins) for caching or optimization.
$parser = new Parser();
$sql = "SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id";
$result = $parser->parse($sql);
// Extract tables/columns
$tables = $result->getTables(); // ['users', 'orders']
$columns = $result->getColumns(); // ['u.name', 'o.total']
Use Case: Rewrite queries for compatibility or performance.
$parser = new Parser();
$sql = "SELECT * FROM users LIMIT 10 OFFSET 20";
$result = $parser->parse($sql);
// Modify the AST (e.g., replace LIMIT/OFFSET with pagination logic)
$rewritten = $result->rewrite(function ($node) {
if ($node instanceof \PMA\SQLParser\Node\Select\Limit) {
return new \PMA\SQLParser\Node\Select\Pagination(
$node->getOffset(),
$node->getCount()
);
}
return $node;
});
echo $rewritten->getSQL(); // Outputs transformed SQL
Use Case: Middleware for SQL validation or query logging.
// app/Http/Middleware/ValidateSQL.php
public function handle($request, Closure $next) {
$parser = new \PMA\SQLParser\Parser();
$parser->parse($request->input('sql')); // Validate raw SQL input
return $next($request);
}
Use Case: Eloquent Query Builder Extension
// Extend Query Builder to parse raw SQL
use PMA\SQLParser\Parser;
class CustomQueryBuilder extends \Illuminate\Database\Query\Builder {
public function parseRawSql($sql) {
$parser = new Parser();
return $parser->parse($sql);
}
}
MySQL Dialect Only
TOP (SQL Server) or FETCH (PostgreSQL) will fail.AST Modification Complexity
tests/ParserTest.php) for node types.var_dump($result) to inspect nodes before rewriting.Performance with Large Queries
Error Messages
try {
$parser->parse($sql);
} catch (\Exception $e) {
\Log::error("Failed to parse SQL: {$sql}", ['error' => $e->getMessage()]);
}
error_reporting(E_ALL) to catch parsing issues early.php vendor/bin/phpunit) to validate your queries.src/Parser/Parser.php if you need custom syntax support (advanced).Custom Node Handlers Add logic to handle unsupported syntax by extending the parser:
$parser = new Parser();
$parser->addListener(new class implements \PMA\SQLParser\Listener {
public function enterNode(\PMA\SQLParser\Node $node) {
if ($node instanceof \PMA\SQLParser\Node\Select) {
// Custom logic for SELECT nodes
}
}
});
Plugin System For reusable transformations, create a plugin:
class PaginationPlugin {
public static function apply(\PMA\SQLParser\Node $node) {
// Rewrite LIMIT/OFFSET to pagination
}
}
Integration with Laravel Scout Use the parser to validate full-text search queries before indexing:
$parser->parse($request->search_query);
// Proceed with Scout indexing
How can I help you explore Laravel packages today?