# 書籍列表頁面
在這個頁面,我們會分頁顯示書籍列表頁面。同時我們也會看到,SF中一個模板是可以被多個控制器復用的。當然,我們還要討論如何編寫分頁。
## 分頁模塊
首先我們看看分頁模塊的編寫。
在`src`目錄下創建一個`lib`目錄,并創建一個`Paginator.php`:
~~~
namespace lib;
class Paginator
{
private $totalPages;
private $page;
private $rpp;
public function __construct($page, $totalcount, $rpp)
{
$this->rpp=$rpp;
$this->page=$page;
$this->totalPages=$this->setTotalPages($totalcount, $rpp);
}
/*
* var recCount: the total count of records
* var $rpp: the record per page
*/
private function setTotalPages($totalcount, $rpp)
{
if ($rpp == 0)
{
$rpp = 20; //This is forced in this. Need to get parameter from configuration but seems not necessary
}
$this->totalPages=ceil($totalcount / $rpp);
return $this->totalPages;
}
public function getTotalPages()
{
return $this->totalPages;
}
public function getPagesList()
{
$pageCount = 5;
if ($this->totalPages <= $pageCount) //Less than total 5 pages
{
return [1, 2, 3, 4, 5];
}
if($this->page <=3)
{
return [1,2,3,4,5];
}
$i = $pageCount;
$r=array();
$half = floor($pageCount / 2);
if ($this->page + $half > $this->totalPages) // Close to end
{
while ($i >= 1)
{
$r[] = $this->totalPages - $i + 1;
$i--;
}
return $r;
} else
{
while ($i >= 1)
{
$r[] = $this->page - $i + $half + 1;
$i--;
}
return $r;
}
}
}
~~~
這個模塊只負責一件事情:根據記錄總數和每頁的記錄數算出總頁面,并根據當前頁數返回一個(合理的)包含前后各2個頁數及當前頁數(共5個)的數組,使得調用端可以顯示去往不同頁面的鏈接。這個類的編寫并不復雜,這里不再做進一步的解釋。
## 書籍列表的路由定義
書籍列表的路由定義比較長,這是因為在設計這個路由(和對應的動作)時,我們考慮要將該路由(和對應的動作)復用。它不僅只是簡單地按照登錄順序的逆序分頁顯示若干書籍,而且還能按照搜索方式的不同只顯示符合搜索條件的若干書籍[1](https://taylorr.gitbooks.io/building-a-web-site-with-symfony/content/05.10%20list.html#fn_1)。
該路由定義如下:
~~~
book_list:
path: /books/list/{type}/{key}/{page}
defaults:
page: 1
type: title
key: all
_controller: AppBundle:Book:list
~~~
這個路由定義的路徑可以解讀為:按照某個類型(`type`)下的關鍵字(`key`)搜索并返回搜索結果中的某一頁(`page`)。
## 書籍列表動作的編寫
由于我們采用API的方式獲得遠程數據,所以控制器中的動作編寫相對簡單:
~~~
public function listAction($page, $key, $type)
{
$uri="http://api/books/list/$type/$key/$page";
$out= json_decode(file_get_contents($uri))->out;
$res=$out->books;
$totalcount=$out->count->bc;
$rpp=$this->container->getParameter('books_per_page');
$paginator = new \lib\Paginator($page, $totalcount, $rpp);
$pagelist = $paginator->getPagesList();
return $this->render("AppBundle:book:list.html.twig", array('res' => $res, 'paginator' => $pagelist, 'cur' => $page, 'total' => $paginator->getTotalPages(), 'key' => $key, 'type' => $type));
}
~~~
簡單說來,我們通過API調用獲得適當的數據(符合搜索條件的書籍和書籍總數),從SF全局配置文件中獲得`books_per_page`這個參數并調用上文提到的`Paginator`類構造一個分頁列表。最后將相應的參數(共6個)傳遞到模板中顯示。
注意:?`books_per_page`參數應該在`/app/config/parameters.yml`中得到定義。方法是在該文件中加入一行:
~~~
books_per_page: 20
~~~
## 書籍列表模板
書籍列表模板比較長,這里不再列出。我們只是重點分析一下分頁導航部分的代碼。
~~~
<section id="pagination" class="col-md-12">
<a href="{{path('book_list', {'page':1, 'key':key, 'type':type})}}" title="首頁"><i class="glyphicon glyphicon-fast-backward"></i></a>
{% if cur==1 %}
<a class="disabled" title="上一頁"><i class="glyphicon glyphicon-backward"></i></a>
{% else %}
<a href="{{path('book_list', {'page':cur-1, 'key':key, 'type':type})}}" title="上一頁"><i class="glyphicon glyphicon-backward"></i></a>
{% endif %}
{% if cur==total %}
<a class="disabled" title="下一頁"><i class="glyphicons forward"></i></a>
{% else %}
<a href="{{path('book_list', {'page':cur+1, 'key': key, 'type':type})}}" title="下一頁"><i class="glyphicon glyphicon-forward"></i></a>
{% endif %}
<a href="{{path('book_list', {'page':total, 'key':key, 'type':type})}}" title="末頁"><i class="glyphicon glyphicon-fast-forward"></i></a>
</section>
~~~
雖然說從`Paginator`獲得的是一個頁面導航列表,但是我們選擇用“前后頁”(加上首頁、末頁)的方式顯示導航按鈕。也因此,我們分離了分頁本身、導航、顯示這三部分。這樣做能提供最大程度的靈活性。
## 效果
至此頁面效果如下:

當然,這個頁面還有一些功能沒有完成。比如搜索以及直接跳轉頁面。搜索會在后續章節講述。直接頁面跳轉比較簡單,請自行完成。
> 1. 目前只支持按照書籍標題起始字符搜索和單一TAG搜索。[??](https://taylorr.gitbooks.io/building-a-web-site-with-symfony/content/05.10%20list.html#reffn_1 "Jump back to footnote [1] in the text.")
- 引言
- 1 LAMP
- 1.1 安裝虛擬機
- 1.2 安裝Vagrant
- 1.3 安裝Ubuntu
- 1.4 安裝Apache 2
- 1.5 安裝PHP
- 1.6 安裝MySQL服務器
- 1.7 最后的微調
- 1.8 設置一個虛擬主機
- 1.9 一個趁手的IDE
- 2 Symfony 3和重要構件
- 2.1 Symfony 3
- 2.2 Doctrine
- 2.3 Twig
- 2.4 Composer
- 3 Symfony重要概念
- 3.1 MVC
- 3.2 Bundle/包
- 3.3 Route/路由
- 3.4 Controller/控制器
- 3.5 Entity/實體
- 3.6 Repository/倉庫
- 3.7 Template/模板
- 3.8 Test/測試
- 4 藏書管理程序的結構
- 5 創建應用
- 5.1 建立版本管理
- 5.2 建立數據庫
- 5.3 應用結構
- 5.4 建立數據庫實體
- 5.5 樣本數據
- 5.6 路由
- 5.7 模板
- 5.8 開始編寫首頁
- 5.9 書籍詳情頁面
- 5.10 書籍列表頁面
- 5.11 書籍搜索
- 6 用戶和后臺
- 7 結語