🔍 DbQuery Builder — API fluida para queries SQL

Actualizado: 2024-12-01

DbQuery es un constructor de queries SQL de tipo fluent que PrestaShop proporciona como alternativa segura a la concatenacion de strings. Siempre genera el SQL a traves de build() y se ejecuta con Db::getInstance().

#Metodos del DbQuery Builder

MetodoSQL generadoDescripcion
select('p.id_product, pl.name')SELECT p.id_product, pl.nameCampos a seleccionar
from('product', 'p')FROM ps_product pTabla principal (con prefijo automatico)
join('JOIN ps_category c...')JOIN ...JOIN literal (con prefijo manual)
leftJoin('table', 'alias', 'on')LEFT JOIN ps_table alias ON ...LEFT JOIN con prefijo automatico
innerJoin('table', 'alias', 'on')INNER JOIN ps_table alias ON ...INNER JOIN
where('p.active = 1')WHERE p.active = 1Condicion (se combinan con AND)
having('cnt > 5')HAVING cnt > 5Condicion HAVING
orderBy('p.date_add DESC')ORDER BY p.date_add DESCOrdenacion
groupBy('p.id_category')GROUP BY p.id_categoryAgrupacion
limit(20, 0)LIMIT 20 OFFSET 0Paginacion (limit, offset)
build()SQL stringGenera el SQL final como string

#Queries con JOIN

Queries complejas con multiples JOINs
php
<?php

// ── Query compleja con multiples joins ──
$query = (new DbQuery())
    ->select('p.id_product, pl.name, p.price, cl.name AS category_name,
              m.name AS manufacturer_name, p.quantity')
    ->from('product', 'p')
    ->leftJoin(
        'product_lang', 'pl',
        'p.id_product = pl.id_product AND pl.id_lang = ' . (int) $idLang
        . ' AND pl.id_shop = ' . (int) $idShop
    )
    ->leftJoin(
        'category_lang', 'cl',
        'p.id_category_default = cl.id_category AND cl.id_lang = ' . (int) $idLang
    )
    ->leftJoin(
        'manufacturer', 'm',
        'p.id_manufacturer = m.id_manufacturer'
    )
    ->innerJoin(
        'stock_available', 'sa',
        'p.id_product = sa.id_product AND sa.id_product_attribute = 0'
    )
    ->where('p.active = 1')
    ->where('p.visibility IN (\'both\', \'catalog\')')
    ->orderBy('p.date_add DESC')
    ->limit(20, ($page - 1) * 20); // Paginacion

$products = Db::getInstance()->executeS($query);

#Filtros WHERE y HAVING

Construccion dinamica de condiciones WHERE
php
<?php

$query = (new DbQuery())
    ->select('p.id_product, pl.name, p.price')
    ->from('product', 'p')
    ->leftJoin('product_lang', 'pl',
        'p.id_product = pl.id_product AND pl.id_lang = ' . (int) $idLang
    );

// ── Condiciones dinamicas ──
if ($activeOnly) {
    $query->where('p.active = 1');
}

if ($minPrice > 0) {
    $query->where('p.price >= ' . (float) $minPrice);
}

if ($maxPrice > 0) {
    $query->where('p.price <= ' . (float) $maxPrice);
}

if ($searchTerm) {
    $term = pSQL($searchTerm);
    $query->where("pl.name LIKE '%" . $term . "%'");
}

if ($idCategory) {
    $query->where('p.id_category_default = ' . (int) $idCategory);
}

// ── HAVING para campos calculados ──
$query
    ->select('COUNT(o.id_order) AS total_orders')
    ->leftJoin('orders', 'o', 'p.id_product = o.id_product')
    ->groupBy('p.id_product')
    ->having('total_orders > 5');

$results = Db::getInstance()->executeS($query);

#Paginacion y ordenacion

Paginacion con DbQuery
php
<?php

$page     = max(1, (int) Tools::getValue('page', 1));
$perPage  = 20;
$offset   = ($page - 1) * $perPage;

// ── Query paginada ──
$query = (new DbQuery())
    ->select('p.id_product, pl.name, p.price')
    ->from('product', 'p')
    ->leftJoin('product_lang', 'pl',
        'p.id_product = pl.id_product AND pl.id_lang = ' . (int) $idLang
    )
    ->where('p.active = 1')
    ->orderBy('p.date_add DESC')
    ->limit($perPage, $offset);

$products = Db::getInstance()->executeS($query);

// ── Contar el total sin LIMIT ──
$countQuery = (new DbQuery())
    ->select('COUNT(p.id_product) AS total')
    ->from('product', 'p')
    ->where('p.active = 1');

$total = (int) Db::getInstance()->getValue($countQuery);
$totalPages = ceil($total / $perPage);

#Subqueries

Subqueries con DbQuery
php
<?php

// ── Subquery en WHERE con IN ──
$categoryIds = [1, 3, 7, 12];
$query = (new DbQuery())
    ->select('*')
    ->from('product', 'p')
    ->where('p.id_category_default IN (' . implode(',', array_map('intval', $categoryIds)) . ')');

// ── Subquery como tabla ──
$subQuery = (new DbQuery())
    ->select('id_order, MAX(date_add) AS last_date')
    ->from('order_history')
    ->groupBy('id_order');

$mainQuery = (new DbQuery())
    ->select('o.id_order, o.reference, oh_last.last_date')
    ->from('orders', 'o')
    ->join('INNER JOIN (' . $subQuery->build() . ') oh_last ON o.id_order = oh_last.id_order')
    ->where('o.valid = 1');

$results = Db::getInstance()->executeS($mainQuery);

#Ejecutar la query

Metodos de Db:: para ejecutar queries
php
<?php

$db = Db::getInstance();

// ── Multiples filas → array de arrays asociativos ──
$rows = $db->executeS($query);  // Devuelve array o false
$rows = $db->executeS($query) ?: [];  // Devuelve array vacio si no hay resultados

// ── Una sola fila → array asociativo ──
$row = $db->getRow($query);
if ($row) {
    echo $row['name'];
}

// ── Un solo valor ──
$count = (int) $db->getValue($query);
$name  = (string) $db->getValue($query);

// ── Obtener el SQL generado para debug ──
$sql = $query->build();
echo $sql;

// ── Debug en modo dev ──
if (_PS_MODE_DEV_) {
    PrestaShopLogger::addLog('SQL: ' . $query->build(), 1);
}
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.