欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简易数据管理案例带有分页展示、新增、删除、修改和服务容器的概念与实际测试

程序员文章站 2022-03-24 21:20:22
...

数据管理案例

获取数据页面

pageData.php 获取前端页面的基本数据,加入了一个小判断

  1. <?php
  2. $dsn = 'mysql:host=localhost;dbname=phpedu';
  3. $username = 'root';
  4. $password = 'root';
  5. $db = new PDO($dsn,$username,$password);
  6. // 设置每页的条数
  7. $num = 2;
  8. // 获取页数,P存在使用p,不存在就使用1
  9. $page = $_GET['p']?? 1;
  10. // 获取总页数,结果需要向上取整CEIL 向上取整,count统计记录
  11. $sql = "SELECT CEIL(COUNT(*) / {$num}) AS `pages` FROM `users` ";
  12. $pages = $db->query($sql)->fetch()['pages'];
  13. // 更多安全设置的$page,当页数小于1 都设置为1 当页数超过总页数设为第一页
  14. if($page <= 1){
  15. $page = 1;
  16. }else if($page > $pages){
  17. $page = 1;
  18. }
  19. // 得到偏移量 (p - 1) * n
  20. $offset = ($page - 1) * $num;
  21. $sql = "SELECT `id`,`name`,`email` FROM `users` LIMIT {$offset}, {$num}";
  22. $users = $db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
  23. // print_r($pages);

分页技术

前端页面test3.php这是完整的页面,上部分是分页的逻辑判断,下部分是渲染部分,表格渲染,分页渲染

  1. <?php
  2. //引入分页数据页面
  3. require 'pageData.php';
  4. // 设置$prev上一页和$next下一页的值
  5. if($page > 1){
  6. $prev = $page -1;
  7. }
  8. if($page < $pages){
  9. $next = $page + 1;
  10. }
  11. // 智能分页的设置
  12. //------------------------------------------------------------------
  13. // 显示页码数量 需要是奇数
  14. $showPages = 5;
  15. // 新的起始页码,只是显示的页码 默认给1
  16. $startPage = 1;
  17. // 新的结束页码 默认给总页数
  18. $endPage = $pages;
  19. // 偏移量:当页数变动成新的时候,起始页码是当前页码减去偏移量,结束页码是当前页码加上偏移量
  20. $offsetPage = ($showPages-1) / 2;
  21. // 前提条件 智能分页 需要展示条数小于总页数才显示
  22. if($showPages < $pages){
  23. // 当前页码要高于偏移量加1 就是 例如这里 页码需要大于 3 以上才可以出现,
  24. // 低于3就是在1、2、3页内前面都没有多余页码,显示来干嘛
  25. if($page > $offsetPage+1 ) $startOmit='...';
  26. // 当前页码大于偏移量的时候就要改变起始页码和结束页码了
  27. if($page > $offsetPage){
  28. $startPage = $page-$offsetPage;
  29. $endPage = $page+$offsetPage;
  30. // 判断结束页是否越界,不允许结束页大于总页数的情况
  31. if($endPage > $pages){
  32. $endPage = $pages;
  33. // 当endPage也就是($page+$offsetPage) 大于总页数,就将endPage设置为总页数
  34. // endPage值改变了,startPage也应该改变,不然显示数量就不对了
  35. $startPage = $pages-($showPages-1);
  36. // 解释:起始页码等于 总页数减去(展示页数减一)
  37. // 举例总页数11 展示页码 5 结束页码等于总页数11 起始页码等于11-5=6 下面的循环从6开始 6 7 8 9 10 11这样就会出现6条
  38. // 减1的话就是11-4=7从 7 8 9 10 11 这样才是正确的起始页码,展示5位页码
  39. }
  40. // 如果小于偏移量起始页就是1 结束页就是显示条数的值
  41. }else{
  42. $startPage = 1;
  43. $endPage = $showPages;
  44. }
  45. // 当前页码大于展示页数,并且当前页码加上偏移量还小于总页码(不包含等于)的情况才显示这个
  46. if( $page+$offsetPage < $pages )$endOmit='...';
  47. }
  48. ?>
  49. <!DOCTYPE html>
  50. <html lang="en">
  51. <head>
  52. <meta charset="UTF-8">
  53. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  54. <title>高端智能的分页条</title>
  55. <link rel="stylesheet" href="style.css">
  56. </head>
  57. <body>
  58. <p>
  59. <a href="">用户登录</a>
  60. </p>
  61. <table>
  62. <caption>用户信息表 <button onclick="location.href='handles.php?action=add'">添加</button></caption>
  63. <thead>
  64. <th>ID</th>
  65. <th>姓名</th>
  66. <th>邮箱</th>
  67. <th>操作</th>
  68. </thead>
  69. <tbody>
  70. <?php foreach($users as $user) :?>
  71. <tr>
  72. <td><?=$user['id']?></td>
  73. <td><?=$user['name']?></td>
  74. <td><?=$user['email']?></td>
  75. <td><button onclick="location.href='handles.php?action=edit&id=<?=$user['id']?>'" >编辑</button>
  76. <button onclick="del(<?=$user['id']?>)">删除</button></td>
  77. </tr>
  78. <?php endforeach ?>
  79. </tbody>
  80. </table>
  81. <p>
  82. <!-- 判断显示 在第一页的时候应该没有首页和上一页的按钮 -->
  83. <?php if($page != 1) :?>
  84. <!-- 固定首页 将p对应值设置为1 -->
  85. <a href="<?=$_SERVER['PHP_SELF'].'?p=1'?>">首页</a>
  86. <!-- 显示上一页 -->
  87. <a href="<?=$_SERVER['PHP_SELF'].'?p='.$prev?>">上一页</a>
  88. <!-- 判断是否有值 -->
  89. <?php if(isset($startOmit)) :?>
  90. <a href="#"><?=$startOmit?></a>
  91. <?php endif ?>
  92. <?php endif ?>
  93. <!-- 循环输出页数 -->
  94. <?php for($i=$startPage; $i<=$endPage; $i++) : ?>
  95. <!-- 当$i等于页码 给class赋值 -->
  96. <?php $active = ($i == $page ) ? 'active' : null; ?>
  97. <a href="<?=$_SERVER['PHP_SELF'].'?p='.$i?>" class="<?=$active?>" ><?=$i?></a>
  98. <?php endfor ?>
  99. <!-- 判断显示 在最后一页的时候应该没有尾页和下一页的按钮 -->
  100. <?php if($page != $pages) :?>
  101. <!-- 判断是否有值 -->
  102. <?php if(isset($endOmit)) :?>
  103. <a href="#"><?=$endOmit?></a>
  104. <?php endif ?>
  105. <!-- 显示下一页 -->
  106. <a href="<?=$_SERVER['PHP_SELF'].'?p='.$next?>">下一页</a>
  107. <!-- 固定尾页 将P对应值设为总页数 -->
  108. <a href="<?=$_SERVER['PHP_SELF'].'?p='.$pages?>">尾页</a>
  109. <?php endif ?>
  110. </p>
  111. </body>
  112. <script>
  113. //确认事件,用户点击确定的时候才跳转URL
  114. function del(id){
  115. let url = 'http://php.edu/0912/handles.php?action=delete&id='+id;
  116. return confirm('是否删除?') ?location.href=url : false;
  117. }
  118. </script>
  119. </html>

在首页不显示上一页和首页,会显示更多按钮…
简易数据管理案例带有分页展示、新增、删除、修改和服务容器的概念与实际测试
完全显示全部按钮
简易数据管理案例带有分页展示、新增、删除、修改和服务容器的概念与实际测试
在尾页不显示下一页和尾页,会显示更多按钮…
简易数据管理案例带有分页展示、新增、删除、修改和服务容器的概念与实际测试

分页总结

  • 计算出符合条件的总页数,CEIL(COUNT(*)) / n,CEIL向上取整,Count统计,*全部或某个字段,n=每页条数
  • 计算偏移量(p-1)*n公式计算,p=页码从1开始,n=每页条数
  • 前端循环出全部页码或部分页码,改变URL中p=页码数,改变显示数据。http://php.edu/0912/test3.php?p=1
  • 基本概念如上,自己可以在此基础上优化,例如案例中固定5位变化显示页码,上下页,首尾页等

其他操作代码,更新,插入,删除

handles.php操作分发器

  1. <?php
  2. // 1.进行数据库连接
  3. $dsn ='mysql:host=localhost;dbname=phpedu';
  4. $username = 'root';
  5. $password = 'root';
  6. $db = new PDO($dsn,$username,$password);
  7. // 2.获取操作类型和id
  8. $action = $_GET['action'];
  9. $id = $_GET['id'];
  10. // 3.操作分发器
  11. switch($action){
  12. case 'edit':
  13. // 3.1引入编辑页码操作
  14. $user = $db->query('SELECT * FROM `users` WHERE id ='.$id)->fetch(PDO::FETCH_ASSOC);
  15. include 'edit.php';
  16. break;
  17. case 'save':
  18. // 3.2保存数据操作
  19. // print_r($_POST);
  20. $sql = 'UPDATE `users` SET `name`=?, `email`=? WHERE `id`=?;';
  21. $stmt = $db->prepare($sql);
  22. if(!empty($_POST)){
  23. $stmt->execute([$_POST['name'], $_POST['email'], $id]);
  24. if($stmt->rowCount()==1){
  25. echo '<script>alert("更新成功");location.href="test3.php";</script>';
  26. }else{
  27. echo "<script>alert('没有数据被更新,请检查内容是否被修改');location.href='test3.php'</script>";
  28. }
  29. }
  30. break;
  31. case 'add':
  32. // 3.3引入新增用户操作
  33. include 'add.php';
  34. break;
  35. case 'saveAdd':
  36. // 3.4 保存新用户数据
  37. // print_r($_POST);
  38. // 可以进行更多的安全判断,和使用数据过滤器
  39. if(empty($_POST['email'])){
  40. echo "<script>alert('请输入邮箱!');location.href='test3.php'</script>";
  41. }
  42. // 实际操作
  43. $sql = 'INSERT INTO `users` SET `name`=?, `email`=? ,`password`=?;';
  44. $stmt = $db->prepare($sql);
  45. $stmt->execute([$_POST['name'], $_POST['email'], sha1($_POST['password'])]);
  46. if($stmt->rowCount()==1){
  47. echo '<script>alert("添加成功");location.href="test3.php";</script>';
  48. }else{
  49. echo "<script>alert('添加失败');location.href='test3.php'</script>";
  50. }
  51. break;
  52. case 'delete':
  53. // 3.5删除操作
  54. $stmt = $db->prepare('DELETE FROM `users` WHERE id=?;');
  55. $stmt->execute([$id]);
  56. if($stmt->rowCount() == 1){
  57. echo '<script>alert("删除成功");location.href="test3.php";</script>';
  58. }
  59. break;
  60. default:
  61. // 默认操作,直接打开此页面跳转回数据页
  62. echo '<script>alert("非法操作");location.href="test3.php";</script>';
  63. }

add.php添加页面

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>用户添加页</title>
  7. </head>
  8. <body>
  9. <form action="<?= $_SERVER['PHP_SELF'].'?action=saveAdd'?>" method="POST" >
  10. <fieldset>
  11. <legend>用户添加</legend>
  12. <p>
  13. <label for="">用户名:</label>
  14. <input type="text" name="name" id="name" >
  15. </p>
  16. <p>
  17. <label for="">邮箱:</label>
  18. <input type="email" name="email" id="email" >
  19. </p>
  20. <p>
  21. <label for="">密码:</label>
  22. <input type="password" name="password" id="password" >
  23. </p>
  24. <p>
  25. <input type="submit" value="提交">
  26. </p>
  27. </fieldset>
  28. </form>
  29. </body>
  30. </html>

edit.php修改页面

  1. <?php
  2. // 编辑表单
  3. // http://php.edu/0912/handle.php?action=edit&id=13
  4. // 从上面的url中解析出id,根据id查询获取对应的用户数据
  5. $user = $pdo->query('select * from users where id='.$id)->fetch();
  6. // print_r($user);
  7. ?>
  8. <!DOCTYPE html>
  9. <html lang="en">
  10. <head>
  11. <meta charset="UTF-8">
  12. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  13. <title>用户编辑</title>
  14. </head>
  15. <body>
  16. <h3>用户编辑</h3>
  17. <form action="<?php echo $_SERVER['PHP_SELF']. '?action=doedit&id='.$id?>" method="post">
  18. <p>
  19. <label for="name">用户名:</label>
  20. <input type="text" id="name" name='name' value="<?=$user['name']?>">
  21. </p>
  22. <p>
  23. <label for="email">邮箱:</label>
  24. <input type="email" name='email' id="email" value="<?=$user['email']?>">
  25. </p>
  26. <p>
  27. <button>保存</button>
  28. </p>
  29. </form>
  30. </body>
  31. </html>

服务容器

Model.php数据获取类

  1. <?php
  2. namespace mvc_test;
  3. // 当声明了命名空间,不进行USE或者是\表示清楚PDO,它就会去找命名空间下的PDO这样是会找不到的
  4. use PDO;
  5. class Model{
  6. public function getData(){
  7. return
  8. (new PDO('mysql:host=localhost;dbname=phpedu','root','root'))
  9. ->query('SELECT id,name,email from users limit 5')
  10. ->fetchAll(PDO::FETCH_ASSOC);
  11. }
  12. }

View.php视图渲染类

  1. <?php
  2. // 视图类
  3. namespace mvc_demo;
  4. class View
  5. {
  6. // 展示模型中的数据
  7. public function fetch($data)
  8. {
  9. $table = '<table>';
  10. $table .= '<caption>用户信息表</caption>';
  11. $table .= '<tr><th>ID</th><th>姓名</th><th>邮箱</th></tr>';
  12. // 遍历用户数据
  13. foreach ($data as $user) {
  14. $table .= '<tr>';
  15. $table .= '<td>'.$user['id'].'</td>';
  16. $table .= '<td>'.$user['name'].'</td>';
  17. $table .= '<td>'.$user['email'].'</td>';
  18. $table .='</tr>';
  19. }
  20. $table .= '</table>';
  21. return $table;
  22. }
  23. }
  24. echo '<style>
  25. table {border-collapse: collapse; border: 1px solid;text-align: center; width: 500px;height: 150px;width: 600px;}
  26. caption {font-size: 1.2rem; margin-bottom: 10px;}
  27. tr:first-of-type { background-color:coral;}
  28. td,th {border: 1px solid; padding:5px}
  29. </style>';

Controller.php控制器页面

  1. <?php
  2. namespace mvc_test;
  3. use closure;
  4. // 匿名函数类。
  5. require __DIR__.DIRECTORY_SEPARATOR.'Model.php';
  6. require __DIR__.DIRECTORY_SEPARATOR.'View.php';
  7. //----------------------------------------------------------------
  8. // 服务容器
  9. class Container{
  10. // 1.对象容器,数组可以存储各种数据包括类实例
  11. protected $instances = [];
  12. // 2.实例绑定到容器中,
  13. // 参数1:对象别名,推荐还是和类名一致
  14. // 参数2:对象, closure声明参数是匿名函数,可以省略
  15. public function bind($alias,closure $process)
  16. {
  17. $this->instances[$alias] = $process;
  18. }
  19. // 3.容器内取出对象(类实例)
  20. public function make($alias,$params=[])
  21. {
  22. // 避免调用影响,使用回调方式去调用
  23. return call_user_func_array($this->instances[$alias],$params);
  24. }
  25. }
  26. // 将依赖的外部对象绑定到服务容器中
  27. $container = new Container();
  28. // 将模型绑定到容器中
  29. $container->bind('model',function(){ return new Model();});
  30. // 将视图绑定到容器中
  31. $container->bind('view',function(){ return new View();});
  32. // print_r($container);die();
  33. //----------------------------------------------------------------
  34. // 控制器
  35. class Controller
  36. {
  37. // 存放服务容器,给其他方式调用
  38. protected $container ='';
  39. // 构造方法,使控制器实例的时候传入服务容器赋值给属性存放
  40. public function __construct(Container $container)
  41. {
  42. $this->container = $container;
  43. }
  44. // 获取数据并展示出来,传入服务容器
  45. public function index()
  46. {
  47. //1. 获取数据
  48. $data = $this->container->make('model')->getData();
  49. // 2. 渲染模板
  50. return $this->container->make('view')->fetch($data);
  51. }
  52. }
  53. // -------------------------------------------------
  54. // 客户端 :测试
  55. // 实例控制器,将服务容器对象作为参数传入
  56. $controller = new Controller($container);
  57. echo $controller->index();

服务容器的总结

  • 简单的服务容器概念
  • 就是将各种模型类,视图类等等的实例化存储到一个类(服务容器)中,这样可以容纳多个类,访问也很简单
  • 控制器创建属性,构造方法存储服务容器,方法需要的时候只需调用这个属性,取出对应的对象进行操作