php 迭代设计模式 -- BookList -- 分页

一、SQL语句

View Code
--
-- 数据库: `booklist`
--

-- --------------------------------------------------------

--
-- 表的结构 `authors`
--

CREATE TABLE IF NOT EXISTS `authors` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

--
-- 转存表中的数据 `authors`
--

INSERT INTO `authors` (`id`, `name`) VALUES
(1, 'admin'),
(2, 'user');

-- --------------------------------------------------------

--
-- 表的结构 `books`
--

CREATE TABLE IF NOT EXISTS `books` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ISBN` varchar(20) CHARACTER SET utf8 DEFAULT NULL,
  `title` varchar(50) CHARACTER SET utf8 DEFAULT NULL,
  `publisher` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ISBN` (`ISBN`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=50 ;

--
-- 转存表中的数据 `books`
--

INSERT INTO `books` (`id`, `ISBN`, `title`, `publisher`) VALUES
(1, '12345678', '测试书本1', 1),
(2, '12345679', '测试书本2', 1),
(3, '0.72667894766357', '测试书本3', 1),
(4, '0.1224353342526', '测试书本4', 1),
(5, '0.43213985900594', '测试书本5', 1),
(6, '0.79339332300554', '测试书本6', 1),
(7, '0.67054706874354', '测试书本7', 1),
(8, '0.97255540543474', '测试书本8', 1),
(9, '0.8511358516767', '测试书本9', 1),
(10, '0.33801307281294', '测试书本10', 1),
(11, '0.13665783976825', '测试书本11', 1),
(12, '0.66925001113606', '测试书本12', 1),
(13, '0.93627656710919', '测试书本13', 1),
(14, '0.67363283287141', '测试书本14', 1),
(15, '0.55933449376313', '测试书本15', 1),
(16, '0.77577400093505', '测试书本16', 1),
(17, '0.2008665541195', '测试书本17', 1),
(18, '0.67701079852601', '测试书本18', 1),
(19, '0.78245436100518', '测试书本19', 1),
(20, '0.88123944018152', '测试书本20', 1),
(21, '0.058834148625689', '测试书本21', 1),
(22, '0.65045245331754', '测试书本22', 1),
(23, '0.075759851444289', '测试书本23', 1),
(24, '0.42744192800246', '测试书本24', 1),
(25, '0.9099301164131', '测试书本25', 1),
(26, '0.26732482879173', '测试书本26', 1),
(27, '0.60683382545303', '测试书本27', 1),
(28, '0.23219467162359', '测试书本28', 1),
(29, '0.34047191249251', '测试书本29', 1),
(30, '0.0057755783254053', '测试书本30', 1),
(31, '0.0074621848831532', '测试书本31', 1),
(32, '0.019984220173195', '测试书本32', 1),
(33, '0.077534576950161', '测试书本33', 1),
(34, '0.32772025496487', '测试书本34', 1),
(35, '0.40599757470749', '测试书本35', 1),
(36, '0.046827139376502', '测试书本36', 1),
(37, '0.016143003493681', '测试书本37', 1),
(38, '0.94023363007254', '测试书本38', 1),
(39, '0.65273917061532', '测试书本39', 1),
(40, '0.44299499359261', '测试书本40', 1),
(41, '0.25675748685073', '测试书本41', 1),
(42, '0.95480248420947', '测试书本42', 1),
(43, '0.0037399912287854', '测试书本43', 1),
(44, '0.15429253424918', '测试书本44', 1),
(45, '0.76024272829317', '测试书本45', 1),
(46, '0.33833606945196', '测试书本46', 1),
(47, '0.41095219311393', '测试书本47', 1),
(48, '0.039752787947424', '测试书本48', 1),
(49, '0.96590739112898', '测试书本49', 1);

-- --------------------------------------------------------

--
-- 表的结构 `book_authors`
--

CREATE TABLE IF NOT EXISTS `book_authors` (
  `bookid` int(11) NOT NULL DEFAULT '0',
  `authorid` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`bookid`,`authorid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- 转存表中的数据 `book_authors`
--

INSERT INTO `book_authors` (`bookid`, `authorid`) VALUES
(1, 2),
(2, 2),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(7, 2),
(8, 2),
(9, 2),
(10, 2),
(11, 1),
(12, 1),
(13, 1),
(14, 1),
(15, 1),
(16, 2),
(17, 2),
(18, 2),
(19, 2),
(20, 2),
(21, 2),
(22, 2),
(23, 2),
(24, 2),
(25, 2),
(26, 2),
(27, 1),
(28, 1),
(29, 1),
(30, 1),
(31, 1),
(32, 1),
(33, 1),
(34, 1),
(35, 1),
(36, 1),
(37, 1),
(38, 2),
(39, 2),
(40, 2),
(41, 2),
(42, 2),
(43, 2),
(44, 2),
(45, 1),
(46, 1),
(47, 1),
(48, 1),
(49, 2);

-- --------------------------------------------------------

--
-- 表的结构 `publisher`
--

CREATE TABLE IF NOT EXISTS `publisher` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

--
-- 转存表中的数据 `publisher`
--

INSERT INTO `publisher` (`id`, `name`) VALUES
(1, '清华大学'),
(2, '北京大学');

二、视图 show.php

<?php
    require_once dirname(__FILE__).'/booklist.class.php';
    require_once dirname(__FILE__).'/page.class.php';
    $dbConn = new mysqli('localhost','root','123456','booklist');
    $dbConn->query("set names utf8");
    $booksPerPage = 10;
    $page = isset($_GET['page']) ? $_GET['page'] : 1;
    $bookList = new BookList($dbConn);
    $bookPage = new Page($bookList,$page,$booksPerPage);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title> 图书俱乐部 </title>
</head>
<body>
    <p>Showing books</p>
    <?php
        printf('%d-%d of %d',$bookPage->getFirstIndex(),$bookPage->getLastIndex(),count($bookList));
    ?>
    <table>
        <thead>
            <th>Title</th>
            <th>Author</th>
            <th>Publisher</th>
        </thead>
        <tbody>
            <?php
                foreach($bookPage as $key => $book)
                {
                    printf('<tr><td>%s</td><td>%s</td><td>%s</td></tr>',$book['title'],$book['author'],$book['publisher']);
                }
            ?>
        </tbody>
    </table>
    <ul>
        <?php
            $totalPages = ceil(count($bookList) / $booksPerPage);
            if($page > 1)
            {
                printf('<li><a href="?page=%d">Prev</a></li>',$page-1);
            }
            for($i = 1 ; $i <= $totalPages ; $i++)
            {
                if( $i == $page)
                {
                    printf('<li>%d</li>', $i);
                } else {
                    printf('<li><a href="?page=%d">%d</a></li>',$i,$i);
                }
            }
            if($page < $totalPages){
                printf('<li><a href="?page=%d">Next</a></li>', $page+1);
            }
        ?>
    </ul>
</body>
</html>
<!--
//系统执行步骤
一、实例化bookList类和page类,bookList实例连接数据库,bookPage实例传入bookList实例,当前页,偏移量
二、外部迭代类bookPage实例调用了rewind()方法,通过getInnerIterator()方法获取内部迭代实例,调用了bookList实例的seek方法
三、bookList实例的seek方法设置了当前索引并获取索引内容
四、bookPage实例的foreach执行了valid()方法,该方法调用了bookList实例的key方法,返回当前迭代实例的key
五、bookPage实例通过验证,执行current()方法,该方法调用了bookList实例的current方法,返回当前内容
六、bookPage实例接着key()方法,该方法调用了bookList实例的key方法,返回当前主键
七、bookPage实例进入next方法,该方法调用了bookList实例的next方法,指针下移
-->

三、BookList类 booklist.class.php

<?php
class BookList implements Iterator,Countable,SeekableIterator,ArrayAccess
{
    private $pages = array();
    private $currentPag = 1;
    private $database = null;
    private $booksPerPage = 10;
    private $totalBooks = 0;
    private $deletions = array();
  public function __construct($database)
  {
        $this->database = $database;
        if($result = $this->database->query("select count(*) from books"))
        {
            if($row = $result->fetch_row())
            {
                $this->totalBooks = $row[0];
            }
        }
  }
    /* 迭代接口 */
  function rewind()
  {
        $this->currentPage = 1;
        if( array_key_exists(1,$this->pages) )
        {
            reset($this->pages[$i]);
        }
  }
  function current()
  {
        return current($this->touchPage());
  }
  function key()
  {
        return key($this->touchPage()) + $this->booksPerPage * ($this->currentPage -1);
  }
  function next()
  {
        $page = & $this->touchPage();
        next($page);
        if( key($page) === null && count($page) == $this->booksPerPage)
        {
            $this->currentPage++;
            $page = & $this->touchPage();
            reset($page);
        }
        return current($page);
  }
  function valid()
  {
        $page = & $this->touchPage();
        return (key($page) !== null);
  }
  //查询数据
  private function & touchPage($pageNo = false)
  {
      if($pageNo === false)
      {
          $pageNo = $this->currentPage;
      }

        if(! array_key_exists($pageNo,$this->pages))
        {
            if( $pageNo > ceil($this->count() / $this->booksPerPage))
            {
                $this->pages[$pageNo] = array();
            }else
            {
        $start = ($pageNo-1)* $this->booksPerPage + $this->getAdjustmentForPage($pageNo);
                $sql = "select `ISBN`,title,(select group_concat(`name`) from `book_authors` as t2 join `authors` as t3 on t2.authorid = t3.id where t2.bookid = t1.id) as `author`,`t4`.`name` as publisher from `books` as t1 join `publisher` as t4 on t1.publisher = t4.id limit $start,{$this->booksPerPage}";
                $result = $this->database->query($sql);
                while ($row = $result->fetch_array(MYSQLI_ASSOC))
                {
                    $temp_array[] = $row;
                }
        $this->pages[$pageNo] = $temp_array;
            }
        }
        $temp = & $this->pages[$pageNo];
        return $temp;
  }
  /* 计数接口 */
  public function count()
  {
        return $this->totalBooks;
  }
  
  /* 索引接口 */
  public function seek($index)
  {
        if($index < 0 || $index > $this->totalBooks)
        {
            throw new OutOfBoundsException();
        }
        $this->currentPage = (int) floor($index / $this->booksPerPage) +1;
        $page = & $this->touchPage();
        reset($page);
        for($i = $index % $this->booksPerPage; $i>0 ; $i--)
        {
            next($page);
        }
  }
  /* 数组访问接口*/
  public function offsetExists($offset)
  {
      echo 'offsetExists';
      return ( $offset > 0 && $offset < count($this) );
  }
  public function offsetGet($offset)
  {
      echo 'offsetGet';
      $pageOfOffset = (int)floor($offset / $this->booksPerPage) + 1;
      $page = & $this->touchPage($pageOfOffset);
      return $page[$offset / $this->booksPerPage];
      
  }
  public function offsetSet($offset,$newValue)
  {
      echo 'offsetSet';      
      $pageOfOffset = (int)floor($offset / $this->booksPerPage) + 1;
      $page = & $this->touchPage($pageOfOffset);
      $page[$offset % $this->booksPerPage] = $newValue;
  }
  public function offsetUnset($offset)
  {
      echo 'offsetUnset';       
      $pageOfOffset = (int)floor($offset / $this->booksPerPage) + 1;
      $page = & $this->touchPage($pageOfOffset);
      $this->deletions[$pageOfOffset] ++;
      ksort($this->deletions);
      unset($page[$offset % $this->booksPerPage]);
      $page = array_values($page);
      while(is_array($this->pages[$pageOfOffset+1]))
      {
          $this->pages[$pageOfOffset][] = array_shift($this->pages[++$pageOfOffset]);
      }
      $record = ($pageOfOffset -1)*$this->booksPerPage + count($this->pages[$pageOfOffset]) + $this->getAdjustmentForPage($pageOfOffset);
      if($result = $this->database->query("select * from books limit $record,1"))
      {
          $this->pages[$pageOfOffset][] = $result->fetch_object();
      }
      $this->totalBooks --;
  }
  private function getAdjustmentForPage($pageNo)
  {
      $adjust = 0;
      for(reset($this->deletions);key($this->deletions) !== null && key($this->deletions) < $pageNo;next($this->deletions))
      {
          $adjust += current($this->deletions);
      }
      return $adjust;
  }
}
?>

四、Page类 page.class.php

<?php
class Page extends IteratorIterator
{
    private $page;
    private $currentItem;
    public $itemsPerPage;

    public function __construct(Iterator $iterator,$page,$itemsPerPage)
    {
    parent::__construct($iterator);
        $this->page = $page;
        $this->itemsPerPage = $itemsPerPage;
        $this->rewind();
    }
    public function getFirstIndex()
    {
        return ($this->page-1) * $this->itemsPerPage;
    }
    public function getLastIndex()
    {
        return $this->getFirstIndex() + $this->itemsPerPage;
    }
  function valid()
  {
        return ( $this->currentItem != $this->itemsPerPage && $this->getInnerIterator()->key() !== null);
  }
  function rewind()
  {
        $currentItem = 0;
        $this->getInnerIterator()->seek( $this->getFirstIndex() );
  }
  function next()
  {
        if( $this->currentItem < $this->itemsPerPage)
        {
            $this->currentItem ++;
            $this->getInnerIterator()->next();
        }
  }  
  function current()
  {
        return ($this->currentItem != $this->itemsPerPage ? $this->getInnerIterator()->current() : null);
  }
  function key()
  {
        return ($this->currentItem != $this->itemsPerPage ? $this->getInnerIterator()->key() : null);
  }


}
?>

 

代码打包下载:PHP迭代设计模式--booklist.zip

 

 

posted @ 2013-03-14 00:46  linzj  阅读(465)  评论(0编辑  收藏  举报