Current File : /var/www/maausk-app/public/products_list.php
<?php
// products_list.php — listado de productos con paginación, filtros y ordenación
// Mostrar errores en desarrollo
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Iniciar sesión si no está activa
if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

require_once __DIR__ . '/db.php';

// Verificar sesión
if (!isset($_SESSION['user_email'])) {
    header('Location: /index.php');
    exit;
}

// Parámetros de orden y paginación
$allowedSort = ['id', 'reference', 'name', 'price', 'initial_quantity'];
$sort = $_GET['sort'] ?? 'name';
if (!in_array($sort, $allowedSort, true)) {
    $sort = 'name';
}
$dir = strtolower($_GET['dir'] ?? 'asc');
if ($dir !== 'asc' && $dir !== 'desc') {
    $dir = 'asc';
}
$page    = max(1, (int)($_GET['page'] ?? 1));
$perPage = 20;
$offset  = ($page - 1) * $perPage;

// Filtros de búsqueda
$filters = [];
$params  = [];
if (isset($_GET['name']) && $_GET['name'] !== '') {
    $filters[] = 'p.name LIKE ?';
    $params[]  = '%' . $_GET['name'] . '%';
}
if (isset($_GET['reference']) && $_GET['reference'] !== '') {
    $filters[] = 'p.reference LIKE ?';
    $params[]  = '%' . $_GET['reference'] . '%';
}
if (isset($_GET['price_min']) && is_numeric($_GET['price_min'])) {
    $filters[] = 'p.price >= ?';
    $params[]  = (float) $_GET['price_min'];
}
if (isset($_GET['price_max']) && is_numeric($_GET['price_max'])) {
    $filters[] = 'p.price <= ?';
    $params[]  = (float) $_GET['price_max'];
}
if (isset($_GET['quantity_min']) && is_numeric($_GET['quantity_min'])) {
    $filters[] = 'p.initial_quantity >= ?';
    $params[]  = (int) $_GET['quantity_min'];
}
if (isset($_GET['quantity_max']) && is_numeric($_GET['quantity_max'])) {
    $filters[] = 'p.initial_quantity <= ?';
    $params[]  = (int) $_GET['quantity_max'];
}

$whereSql = '';
if ($filters) {
    $whereSql = 'WHERE ' . implode(' AND ', $filters);
}

// Debug (quitar en producción)
echo '<!-- WHERE: ' . $whereSql . ' -->';
echo '<!-- PARAMS: ' . implode(', ', array_map('htmlspecialchars', $params)) . ' -->';

// Contar total de registros
$countSql = "SELECT COUNT(*) FROM products p $whereSql";
$countStmt = $pdo->prepare($countSql);
$countStmt->execute($params);
$total = (int)$countStmt->fetchColumn();
$totalPages = (int)ceil($total / $perPage);

// Consulta principal con límites interpolados (offset y limit son enteros validados)
$sql = sprintf(
    "SELECT p.id, p.reference, p.name, p.price, p.initial_quantity
     FROM products p
     %s
     ORDER BY %s %s
     LIMIT %d, %d",
    $whereSql,
    $sort,
    $dir,
    $offset,
    $perPage
);
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$products = $stmt->fetchAll();

// Función para generar enlaces de ordenación
function sortLink($column, $label) {
    global $sort, $dir;
    $newDir = ($sort === $column && $dir === 'asc') ? 'desc' : 'asc';
    $icon = '';
    if ($sort === $column) {
        $icon = $dir === 'asc' ? ' ↑' : ' ↓';
    }
    $qs = $_GET;
    $qs['sort'] = $column;
    $qs['dir']  = $newDir;
    $url = '?' . http_build_query($qs);
    return "<a href='".htmlspecialchars($url)."'>".htmlspecialchars($label)."{$icon}</a>";
}
?>
<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Listado de Productos | Pharmacius</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
  <link href="/css/style.css" rel="stylesheet">
</head>
<body class="d-flex">

  <?php require_once __DIR__ . '/sidebar.php'; ?>

  <main id="content" class="flex-grow-1 p-4">
    <h2 class="mb-4">Listado de Productos</h2>

    <!-- Filtros de búsqueda -->
    <form method="get" class="row g-3 mb-4">
      <div class="col-md-3">
        <label class="form-label">Nombre</label>
        <input type="text" name="name" value="<?= htmlspecialchars($_GET['name'] ?? '') ?>" class="form-control" placeholder="Buscar nombre">
      </div>
      <div class="col-md-2">
        <label class="form-label">Referencia</label>
        <input type="text" name="reference" value="<?= htmlspecialchars($_GET['reference'] ?? '') ?>" class="form-control" placeholder="Buscar ref.">
      </div>
      <div class="col-md-2">
        <label class="form-label">Precio Min</label>
        <input type="number" step="0.01" name="price_min" value="<?= htmlspecialchars($_GET['price_min'] ?? '') ?>" class="form-control">
      </div>
      <div class="col-md-2">
        <label class="form-label">Precio Máx</label>
        <input type="number" step="0.01" name="price_max" value="<?= htmlspecialchars($_GET['price_max'] ?? '') ?>" class="form-control">
      </div>
      <div class="col-md-3 d-flex align-items-end">
        <button class="btn btn-primary me-2">Buscar</button>
        <a href="products_list.php" class="btn btn-secondary">Reiniciar</a>
      </div>
    </form>

    <?php if (empty($products)): ?>
      <div class="alert alert-info">No hay productos que coincidan.</div>
    <?php else: ?>
      <div class="table-responsive">
        <table class="table table-striped table-hover">
          <thead class="table-light">
            <tr>
              <th><?= sortLink('id','ID') ?></th>
              <th><?= sortLink('reference','Referencia') ?></th>
              <th><?= sortLink('name','Nombre') ?></th>
              <th><?= sortLink('price','Precio (€)') ?></th>
              <th><?= sortLink('initial_quantity','Cantidad') ?></th>
            </tr>
          </thead>
          <tbody>
            <?php foreach ($products as $prod): ?>
              <tr>
                <td><?= htmlspecialchars($prod['id']) ?></td>
                <td><?= htmlspecialchars($prod['reference']) ?></td>
                <td><?= htmlspecialchars($prod['name']) ?></td>
                <td><?= number_format($prod['price'],2) ?></td>
                <td><?= (int)$prod['initial_quantity'] ?></td>
              </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
      </div>

      <!-- Paginación -->
      <nav aria-label="Paginación" class="mt-4">
        <ul class="pagination">
          <?php if ($page > 1): ?>
            <?php $qs = $_GET; $qs['page']=$page-1; ?>
            <li class="page-item"><a class="page-link" href="?<?= http_build_query($qs) ?>">Anterior</a></li>
          <?php endif; ?>
          <?php for ($p=1; $p<=$totalPages; $p++): ?>
            <?php $qs['page']=$p; ?>
            <li class="page-item <?= $p=== $page?'active':'' ?>">
              <a class="page-link" href="?<?= http_build_query($qs) ?>"><?= $p ?></a>
            </li>
          <?php endfor; ?>
          <?php if ($page < $totalPages): ?>
            <?php $qs['page']=$page+1; ?>
            <li class="page-item"><a class="page-link" href="?<?= http_build_query($qs) ?>">Siguiente</a></li>
          <?php endif; ?>
        </ul>
      </nav>
    <?php endif; ?>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>