显示多维数组并累计总数

如何正确显示多维数组中的数据,一直是任何一个Web开发人员的经典问题。为了说明问题,假设你希望显示一个客户和他们的购买清单。对于每个客户,你希望显示他们的姓名、电话号码、账户余额等。这已经代表了一个二维数组,其中x轴代表客户,y轴代表该客户的数据。现在加入购买的数据,你就有了第三个轴! 如何在二维屏幕上表示一个三维模型?一个可能的解决方案是将 “隐藏 “的分割标签与一个简单的JavaScript可见性切换结合起来。

如何做…

1.首先,我们需要从一个使用了许多JOIN子句的SQL语句中生成一个3D数组。我们将使用第1章 《建立基础》中介绍的 Application/Database/Connection 来制定一个合适的SQL查询。为了支持分页,我们开放了两个参数:minmax。不幸的是,在这种情况下,我们不能使用简单的LIMITOFFSET,因为行数会根据任何给定客户的购买数量而变化。相应地,我们可以通过对客户ID的限制来限制行数,这个限制大概(希望)是递增的。为了使这个工作正常进行,我们还需要将主order 设置为customer ID。

  1. define('ITEMS_PER_PAGE', 6);
  2. define('SUBROWS_PER_PAGE', 6);
  3. define('DB_CONFIG_FILE', '/../config/db.config.php');
  4. include __DIR__ . '/../Application/Database/Connection.php';
  5. use Application\Database\Connection;
  6. $conn = new Connection(include __DIR__ . DB_CONFIG_FILE);
  7. $sql = 'SELECT c.id,c.name,c.balance,c.email,f.phone, '
  8. . 'u.transaction,u.date,u.quantity,u.sale_price,r.title '
  9. . 'FROM customer AS c '
  10. . 'JOIN profile AS f '
  11. . 'ON f.id = c.id '
  12. . 'JOIN purchases AS u '
  13. . 'ON u.customer_id = c.id '
  14. . 'JOIN products AS r '
  15. . 'ON u.product_id = r.id '
  16. . 'WHERE c.id >= :min AND c.id < :max '
  17. . 'ORDER BY c.id ASC, u.date DESC ';
  1. 接下来我们可以根据对客户ID的限制,使用简单的$_GET参数实现一种分页形式。请注意,我们添加了一个额外的检查,以确保$prev的值不会低于零。你可以考虑添加另一个控件,确保$next的值不超过最后一个客户ID。在本例中,我们只允许它递增。
  1. $page = $_GET['page'] ?? 1;
  2. $page = (int) $page;
  3. $next = $page + 1;
  4. $prev = $page - 1;
  5. $prev = ($prev >= 0) ? $prev : 0;
  1. 然后我们计算$min$max的值,并准备和执行SQL语句。
  1. $min = $prev * ITEMS_PER_PAGE;
  2. $max = $page * ITEMS_PER_PAGE;
  3. $stmt = $conn->pdo->prepare($sql);
  4. $stmt->execute(['min' => $min, 'max' => $max]);
  1. 可以使用while()循环来获取结果。在这个例子中,我们使用PDO::FETCH_ASSOC的简单获取模式。使用客户ID作为键,我们将客户的基本信息存储为数组参数。然后我们在一个子数组中存储一个购买信息的数组,$results[$key]['purchases'][]。当客户ID发生变化时,就是一个信号,为下一个客户存储同样的信息。需要注意的是,我们将每个客户的总数累积在数组key total中。
  1. $custId = 0;
  2. $result = array();
  3. $grandTotal = 0.0;
  4. while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  5. if ($row['id'] != $custId) {
  6. $custId = $row['id'];
  7. $result[$custId] = [
  8. 'name' => $row['name'],
  9. 'balance' => $row['balance'],
  10. 'email' => $row['email'],
  11. 'phone' => $row['phone'],
  12. ];
  13. $result[$custId]['total'] = 0;
  14. }
  15. $result[$custId]['purchases'][] = [
  16. 'transaction' => $row['transaction'],
  17. 'date' => $row['date'],
  18. 'quantity' => $row['quantity'],
  19. 'sale_price' => $row['sale_price'],
  20. 'title' => $row['title'],
  21. ];
  22. $result[$custId]['total'] += $row['sale_price'];
  23. $grandTotal += $row['sale_price'];
  24. }
  25. ?>
  1. 接下来我们实现视图逻辑。首先,我们从一个显示主要客户信息的块开始。
  1. <div class="container">
  2. <?php foreach ($result as $key => $data) : ?>
  3. <div class="mainLeft color0">
  4. <?= $data['name'] ?> [<?= $key ?>]
  5. </div>
  6. <div class="mainRight">
  7. <div class="row">
  8. <div class="left">Balance</div>
  9. <div class="right"><?= $data['balance']; ?></div>
  10. </div>
  11. <div class="row">
  12. <div class="left color2">Email</div>
  13. <div class="right"><?= $data['email']; ?></div>
  14. </div>
  15. <div class="row">
  16. <div class="left">Phone</div>
  17. <div class="right"><?= $data['phone']; ?></div>
  18. </div>
  19. <div class="row">
  20. <div class="left color2">Total Purchases</div>
  21. <div class="right">
  22. <?= number_format($data['total'],2); ?>
  23. </div>
  24. </div>
  1. 接下来是显示这个客户的购买清单的逻辑。
  1. <!-- Purchases Info -->
  2. <table>
  3. <tr>
  4. <th>Transaction</th><th>Date</th><th>Qty</th>
  5. <th>Price</th><th>Product</th>
  6. </tr>
  7. <?php $count = 0; ?>
  8. <?php foreach ($data['purchases'] as $purchase) : ?>
  9. <?php $class = ($count++ & 01) ? 'color1' : 'color2'; ?>
  10. <tr>
  11. <td class="<?= $class ?>"><?= $purchase['transaction'] ?></td>
  12. <td class="<?= $class ?>"><?= $purchase['date'] ?></td>
  13. <td class="<?= $class ?>"><?= $purchase['quantity'] ?></td>
  14. <td class="<?= $class ?>"><?= $purchase['sale_price'] ?></td>
  15. <td class="<?= $class ?>"><?= $purchase['title'] ?></td>
  16. </tr>
  17. <?php endforeach; ?>
  18. </table>
  1. 为了分页的目的,我们添加按钮来代表上一个和下一个。
  1. <?php endforeach; ?>
  2. <div class="container">
  3. <a href="?page=<?= $prev ?>">
  4. <input type="button" value="Previous"></a>
  5. <a href="?page=<?= $next ?>">
  6. <input type="button" value="Next" class="buttonRight"></a>
  7. </div>
  8. <div class="clearRow"></div>
  9. </div>
  1. 遗憾的是,到目前为止,结果还远没有达到整洁的程度。因此,我们添加了一个简单的JavaScript函数来根据id属性来切换<div>标签的可见性。
  1. <script type="text/javascript">
  2. function showOrHide(id) {
  3. var div = document.getElementById(id);
  4. div.style.display = div.style.display == "none" ? "block" : "none";
  5. }
  6. </script>
  1. 接下来,我们将Purchases表包装在最初不可见的 <div> 标签内。 然后,我们可以限制最初可见的子行数,并添加一个链接来显示剩余的购买数据。
  1. <div class="row" id="<?= 'purchase' . $key ?>" style="display:none;">
  2. <table>
  3. <tr>
  4. <th>Transaction</th><th>Date</th><th>Qty</th>
  5. <th>Price</th><th>Product</th>
  6. </tr>
  7. <?php $count = 0; ?>
  8. <?php $first = TRUE; ?>
  9. <?php foreach ($data['purchases'] as $purchase) : ?>
  10. <?php if ($count > SUBROWS_PER_PAGE && $first) : ?>
  11. <?php $first = FALSE; ?>
  12. <?php $subId = 'subrow' . $key; ?>
  13. </table>
  14. <a href="#" onClick="showOrHide('<?= $subId ?>')">More</a>
  15. <div id="<?= $subId ?>" style="display:none;">
  16. <table>
  17. <?php endif; ?>
  18. <?php $class = ($count++ & 01) ? 'color1' : 'color2'; ?>
  19. <tr>
  20. <td class="<?= $class ?>"><?= $purchase['transaction'] ?></td>
  21. <td class="<?= $class ?>"><?= $purchase['date'] ?></td>
  22. <td class="<?= $class ?>"><?= $purchase['quantity'] ?></td>
  23. <td class="<?= $class ?>"><?= $purchase['sale_price'] ?></td>
  24. <td class="<?= $class ?>"><?= $purchase['title'] ?></td>
  25. </tr>
  26. <?php endforeach; ?>
  27. </table>
  28. <?php if (!$first) : ?></div><?php endif; ?>
  29. </div>
  1. 然后我们添加一个按钮,当点击时,就会显示出隐藏的<div>标签。
  1. <input type="button" value="Purchases" class="buttonRight"
  2. onClick="showOrHide('<?= 'purchase' . $key ?>')">

如何运行…

将步骤1至步骤5中描述的代码放入 chap_10_html_table_multi_array_hidden.php 文件中。

while()循环中添加以下内容。

  1. printf('%6s : %20s : %8s : %20s' . PHP_EOL,
  2. $row['id'], $row['name'], $row['transaction'], $row['title']);

就在 while() 循环之后,添加一条退出命令。下面是输出结果。

显示多维数组并累计总数 - 图1

你会注意到,基本的客户信息,如ID和姓名,在每条结果行中都会重复,但购买信息,如交易和产品名称,则有所不同。继续删除printf()语句。

将退出命令改为:

  1. echo '<pre>', var_dump($result), '</pre>'; exit;

下面是新组成的3D阵列的样子。

显示多维数组并累计总数 - 图2

现在可以添加步骤5至7中所示的显示逻辑。如前所述,虽然你现在显示的是所有数据,但可视化显示并没有什么帮助。现在继续添加剩余步骤中提到的细化内容。下面是初始输出可能出现的情况。

显示多维数组并累计总数 - 图3

当点击 “购买 “按钮时,会出现初始购买信息。如果点击 “更多 “链接,则显示剩余的购买信息。

显示多维数组并累计总数 - 图4