Query Builder
Query builder-ul db() oferă acces direct la baza de date fără a trece prin modele ORM. Este util pentru interogări complexe, agregări, DDL și operațiuni care nu se potrivesc pe un singur model.
User::where(...)->get(). Pentru agregări, JOIN-uri pe mai multe tabele, DDL sau SQL brut, folosește db(). Cele două pot fi combinate liber.Funcția db()
// Conexiunea implicită (din config/database.php)
$conn = db();
// Conexiune numită
$conn = db('company');
$conn = db('workleto');
// Dotted notation: instance + database override
$conn = db('workleto.company_data');Funcția returnează o instanță Connection care expune builder-e fluente pentru fiecare tip de operațiune.
SELECT
// Select simplu
$users = db('company')
->select('id', 'name', 'email')
->from('users')
->where('active', 1)
->orderBy('name')
->limit(10)
->resultset();
// Select cu *
$all = db()->select('*')->from('modules')->resultset();
// O singură coloană
$names = db('company')
->select('name')
->from('users')
->col();
// Un singur rând
$user = db('company')
->select('*')
->from('users')
->where('id', 1)
->single();
// O singură celulă (prima celulă a primului rând)
$name = db('company')
->select('name')
->from('users')
->where('id', 1)
->cell();Numărare și existență
Pentru numărat sau verificat existența, folosește helper-ele dedicate. Nu scrie COUNT(*) manual:
// Câte rânduri se potrivesc
$total = db('company')->select()->from('users')->where('active', 1)->count();
// Există măcar un rând? (rulează SELECT 1 ... LIMIT 1)
$hasAdmin = db('company')->select()->from('users')->where('role', 'admin')->exists();
// Valori distincte
$roles = db('company')->select('role')->from('users')->distinct()->col();WHERE
db('company')->select()->from('users')
->where('status', 'active') // egal
->where('age', '>', 18) // operator explicit
->where('name', 'LIKE', '%Ion%') // LIKE
->where('id', 'IN', [1, 2, 3]) // IN
->where('deleted_at', null) // IS NULL
->orWhere('role', 'admin') // OR
->whereGroup(function ($q) { // grup cu paranteze
$q->where('a', 1)->orWhere('b', 2);
})
->resultset();JOIN, GROUP BY, HAVING
use Leto\Database\QueryBuilder\Enums\JoinType;
db('company')
->select('u.name', 'COUNT(o.id) as order_count')
->from('users u')
->join(JoinType::LEFT, 'orders o', 'u.id = o.user_id')
->groupBy('u.id')
->having('order_count', '>', 5)
->orderBy('order_count', 'DESC')
->resultset();db(), orderBy() primește direcția ca string ('ASC' / 'DESC'). Enum-ul Order aparține stratului ORM (Model::...->orderBy(...)), nu query builder-ului: dacă îl pasezi aici, primești un TypeError.Paginare
$results = db('company')
->select('*')
->from('users')
->orderBy('name')
->page(1, 20) // pagina 1, câte 20
->resultset();INSERT
// Inserare simplă
db('company')->insert('users', [
'name' => 'Ion Popescu',
'email' => 'ion@example.com',
])->execute();
// Obține ID-ul inserat
$id = db('company')->insert_id();Exemplu real:
db()->insert('companies', [
'name' => $nume,
'namespace' => $namespace,
'package' => $package,
])->execute();UPDATE
db('company')
->update('users')
->set('name', 'Nume nou')
->set('email', 'email@nou.com')
->where('id', 1)
->execute();Exemplu real:
db('company')->update('company_api_tokens', [
'last_used' => date('Y-m-d H:i:s'),
'count' => $token['count'] + 1,
])
->where('token_uuid', $tokenUuid)
->execute();DELETE
db('company')
->delete('users')
->where('id', 1)
->execute();Exemplu real:
db()->delete('modules')
->where('module_name', $moduleName)
->execute();Tranzacții
db('company')->withTransaction(function () {
db('company')->insert('orders', ['total' => 100])->execute();
$orderId = db('company')->insert_id();
db('company')->insert('order_items', [
'order_id' => $orderId,
'product_id' => 5,
'quantity' => 2,
])->execute();
});Metoda withTransaction() execută closure-ul într-o tranzacție: face commit automat la final sau rollback dacă apare o excepție.
DDL
// CREATE TABLE
db()->createTable('logs')
->column('id', 'INT')
->column('message', 'VARCHAR(500)')
->column('context', 'TEXT')
->column('created_at', 'TIMESTAMP')
->autoIncrement('id')
->execute();
// ALTER TABLE
db()->alter('users')
->addColumn('phone', 'VARCHAR(20)')
->execute();
// DROP TABLE
db()->dropTable('temp_data')->execute();
// TRUNCATE
db()->truncate('sessions')->execute();Enum-uri
JoinType — tipuri de JOIN
namespace Leto\Database\QueryBuilder\Enums;
enum JoinType
{
case INNER;
case LEFT;
case RIGHT;
}Folosit cu metoda join() în loc de shortcut-urile leftJoin()/innerJoin()/rightJoin():
use Leto\Database\QueryBuilder\Enums\JoinType;
db('company')
->select('u.*', 'o.total')
->from('users u')
->join(JoinType::INNER, 'orders o', 'u.id = o.user_id')
->resultset();SQL brut
Când o interogare nu se poate exprima prin builder-ul fluent (funcții de fereastră, CTE, sintaxă specifică), folosește query() cu parametri legați (bound):
$rows = db('company')
->query('SELECT * FROM users WHERE created_at > :from AND role = :role', [
'from' => '2026-01-01',
'role' => 'admin',
])
->resultset();Valorile din al doilea argument sunt întotdeauna legate ca parametri (protejate împotriva SQL injection). query() returnează un statement pe care poți apela resultset(), single(), cell() sau col(), la fel ca la builder.
cell(), single(), col(), resultset()
| Metodă | Returnează |
|---|---|
resultset() | array de rânduri (array-uri asociative) |
single() | Un singur rând (array asociativ) sau false dacă nu găsește nimic |
cell() | O singură valoare: prima celulă a primului rând (sau coloana cu numele dat: cell('nume')) |
col() | Un array cu valorile unei singure coloane |
Conexiuni multiple
// Conectare la baza de date a unei companii specifice
$db = db('workleto.' . DB_PREFIX_COMPANY_DATA . $companyNamespace);
$data = $db->select('*')->from('users')->resultset();Dotted notation-ul workleto.nume_db refolosește configurația instanței workleto dar schimbă baza de date.