atlas/statement
Atlas.Statement provides portable SQL statement builders for MySQL, PostgreSQL, SQLite, and SQL Server. Connection-independent and works well with PDO, Atlas.Query, and Atlas.Pdo to build queries safely and consistently across databases.
Installation:
composer require atlas/statement
No additional configuration is required—just autoload the package.
First Use Case:
Build a simple SELECT query:
use Atlas\Statement\Select;
$select = new Select('users');
$select->where('active', true);
$select->limit(10);
echo $select->getSql(); // "SELECT * FROM users WHERE active = ? LIMIT 10"
Where to Look First:
src/Statement/ directory for core classes (Select, Insert, Update, Delete).tests/ for usage examples and edge cases.Query Building: Chain methods for fluent query construction:
$select = (new Select('posts'))
->where('published_at', '>', now())
->orderBy('created_at', 'desc')
->limit(50);
Parameter Binding: Automatically escapes values (works with PDO):
$select = (new Select('products'))
->where('name', 'like', '%' . $searchTerm . '%');
$stmt = $pdo->prepare($select->getSql());
$stmt->execute($select->getParams());
Table-Specific Statements:
$insert = (new Insert('users'))
->set(['name' => 'John', 'email' => 'john@example.com']);
$update = (new Update('users'))
->where('id', 1)
->set(['status' => 'active']);
Joins and Subqueries:
$select = (new Select('orders'))
->join('users', 'orders.user_id = users.id')
->whereSub(
(new Select('payments'))
->whereColumn('orders.id', 'payments.order_id')
->where('payments.status', 'paid')
->select('COUNT(*) as paid_count'),
'> 0'
);
Dynamic Table/Column Handling:
Use getTable() (v1.1+) to inspect the target table:
$update = new Update('users');
$table = $update->getTable(); // Returns 'users'
Atlas\Query for execution:
$query = new Atlas\Query($pdo);
$results = $query->run($select);
DB::select((new Select('complex_view'))->getSql(), $select->getParams());
Atlas\Statement\Statement to support non-PDO drivers (e.g., Doctrine DBAL).Parameter Binding:
$statement->getParams() with execute():
$stmt->execute($select->getParams()); // Correct
$stmt->execute(); // ❌ Missing params!
whereEquals() (fixed in v1.0.1) may cause SQL errors. Test with [] values.LIMIT/OFFSET:
UPDATE/DELETE statements ignore limit()/offset() by default (fixed in v1.0.1).
Fix: Explicitly chain them if needed:
$delete = (new Delete('logs'))
->where('created_at', '<', now()->subDays(30))
->limit(1000); // Works post-v1.0.1
Database-Specific Syntax:
raw()) may not translate to all databases.
Fix: Use database-specific builders or validate SQL before execution:
if ($db === 'sqlite') {
$select->whereRaw('UPPER(name) = ?', ['JOHN']); // SQLite uses UPPER()
}
Table/Column Validation:
echo $statement->getSql(); // Debug raw SQL
print_r($statement->getParams()); // Debug bound params
// @phpstan-ignore-next-line
$select->where('column', 'value');
Atlas\Statement\TestCase (if available) or mock PDO for unit tests:
$pdo = $this->createMock(PDO::class);
$pdo->method('prepare')->willReturnSelf();
$pdo->method('execute')->willReturn(true);
Atlas\Statement\Condition to add database-specific functions:
class MyCustomCondition extends Condition {
public function jsonContains(string $column, mixed $value): self {
return $this->whereRaw("JSON_CONTAINS({$column}, ?)", [$value]);
}
}
class LoggingStatement {
public function __construct(private Statement $statement) {}
public function getSql(): string {
\Log::debug('Executing: ' . $this->statement->getSql());
return $this->statement->getSql();
}
}
class PostgreSQLSelect extends Select {
public function jsonbPath(string $column, string $path): self {
return $this->whereRaw("({$column}) ? {$path}", ['->']);
}
}
How can I help you explore Laravel packages today?