適当な思いつきで書くブログ

UbuntuやPerlやJavaScriptやVimやZshやShellScriptやMySQLと戯れている中で適当な思いつきでやってみたことを書いています。

Data:Pageset使ってページングをスマートに(Perl:2.5日目)

私用(引越)のため更新が滞っておりました。自宅にネット環境が整うまではもうちょっと滞るかも知れません><

テーマ:前回イマイチだったページングをCPANを使って処理を簡素化する

前回作成した検索結果リスト表示はページングの処理がダラダラと長くなってしまい醜い結果となってしまいましたので、id:holidays-lさんに教えてもらったData::Pageモジュールを使用せずにw(ごめんなしあー)、似た感じのData::Pagesetを利用してソースをスマートにしてみます。

念のため

はじめData:Pageを試したのですがページングを表示したいように表示できなかったぽいので、Data:Pagesetを使用した次第であります。

Data::Pagesetはこんなに便利

Data::Pagesetの解説記事があまりなかったので自分が利用したあたりだけちょっと書きます。

今回、表示したい内容は下記の通りです。

  • 1ページあたりのページング数は10ページ(もちろん10ページ分なければあるだけ)
  • 「前へ」と「次へ」のリンク
  • ページが進むごとにページングをスライド


まずは各パラメータを設定します。

リスト1

my $page_info = Data::Pageset->new({
  'total_entries'    => $total_entries,    #すべての要素数(全ヒット数)
  'entries_per_page' => $entries_per_page, #1ページあたりの要素表示数
  'current_page'     => $current_page,     #現在のページ
  'pages_per_set'    => $pages_per_set,    #1ページあたりのページング数 => 10
  'mode'             => 'slide',           #ページングを表示ページ幅を固定するかスライドするか
                                           #'slide' or 'fixed'
});
1)1ページあたりのページング数は10ページ(もちろん10ページ分なければあるだけ)

リスト1の'pages_per_set'を10に設定することでほぼ完了です。

あとは"$page_info->pages_in_set()"に表示すべきページが入っていますので、これをリスト2のように出力するだけでページングは完了です。
"もちろん10ページ分なければあるだけ"というのもモジュールが勝手にやってくれちゃいます。


リスト2

foreach my $page (@{$page_info->pages_in_set()}) {
  if($page == $page_info->current_page()) {
    print "<strong>$page</strong>";
  } else {
    print "<a href='?page=" . $page . "'>$page</a>";
  }
}
2)「前へ」と「次へ」のリンク

「前へ」ページのページ番号は"$page_info->next_page"で、「次へ」ページのページ番号は"$page_info->next_page"で取得できます。

「前へ」と「次へ」はそれぞれ現在のページ番号からそれぞれ-1, +1したものになりますが、当然最初のページには「前へ」が、最後のページには「次へ」がありませんので、if文でその有無を判定しtrueであれば出力します。


リスト3

#前へ
if ($page_info->previous_page) {
  print "<a href='?page=" . $page_info->previous_page . "'>&lt;&lt;&nbsp;前へ</a>\n";
}

#次へ
if ($page_info->next_page) {
  print "<a href='?page=" . $page_info->next_page . "'>次へ&nbsp;&gt;&gt;</a>\n";
}
3)ページが進むごとにページングをスライド

この表示形式(Google検索結果表示と同様)が世の中の基本だと思うのですが、例えば1ページあたりのページング数を10ページの場合、10ページ目までは

1 2 3 4 5 6 7 8 9 10

11ページ目からは

11 12 13 14 15 16 17 18 19 20

のような表示形式も可能です。

今回の場合はリスト1の"'mode' => 'slide'"で設定が完了です。

結果:できました

CPANモジュールはすごく便利ですね。あっという間にできてしまいました。

正直なところPerlの勉強になっていない気がしてきましたが…。

デモはこちら


ソースは下記


20080321.pl(perl)

#!/usr/bin/env perl

use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use XML::TreePP;
use HTML::Template;
use HTML::Template::Compiled;
use Data::Pageset;

my $q = CGI->new;
my $ItemPage = $q->param('ItemPage') || "1";
my $SearchIndex = $q->param('SearchIndex') || "DVD";
my $Keywords = $q->param('Keywords') || "Perl";


my $tpp = XML::TreePP->new(force_array => [ "Item", "Author" ]);
my $req_url = "http://webservices.amazon.co.jp/onca/xml?SearchIndex=" . $SearchIndex . "&Keywords=" . $Keywords . "&ItemPage=" . $ItemPage . "&ResponseGroup=Small&Operation=ItemSearch&Service=AWSECommerceService&AWSAccessKeyId=/*あなたのAmazonアクセスキー*/";
my $tree = $tpp->parsehttp(GET => $req_url);

my $template = HTML::Template::Compiled->new(
  filename => '20080321.tmpl',
);


#ページング
my $paging_html = '';

#現在のページ
my $current_page = $tree->{ItemSearchResponse}->{Items}->{Request}->{ItemSearchRequest}->{ItemPage};

#要素の全体数
my $total_entries = $tree->{ItemSearchResponse}->{Items}->{TotalResults};

#1ページあたりの表示要素数
my $entries_per_page =10;

#ページング数
my $pages_per_set = 10;

my $page_info = Data::Pageset->new({
  'total_entries'       => $total_entries, 
  'entries_per_page'    => $entries_per_page, 
  'current_page'        => $current_page,
  'pages_per_set'       => $pages_per_set,
  'mode'                => 'slide', # default, or 'slide'
});


#リンク先URL(除:ItemPageのvalue)
my $href = "?SearchIndex=" . $tree->{ItemSearchResponse}->{Items}->{Request}->{ItemSearchRequest}->{SearchIndex}
         . "&Keywords=" . $tree->{ItemSearchResponse}->{Items}->{Request}->{ItemSearchRequest}->{Keywords}
         . "&ItemPage=";


#前へ
if ($page_info->previous_page) {
  $paging_html  .= "<a href='" . $href . $page_info->previous_page . "'>&lt;&lt;&nbsp;前へ</a>\n";
}

#ページ別リンク
foreach my $page (@{$page_info->pages_in_set()}) {
  if($page == $page_info->current_page()) {
    $paging_html .= "&nbsp;<strong>$page</strong>\n&nbsp;";
  } else {
    $paging_html .= "&nbsp;<a href='" . $href . $page . "'>$page</a>\n&nbsp;";
  }
}

#次へ
if ($page_info->next_page) {
  $paging_html  .= "<a href='" . $href . $page_info->next_page . "'>次へ&nbsp;&gt;&gt;</a>\n";
}


$template->param(Item => $tree->{ItemSearchResponse}->{Items}->{Item});
$template->param(Request => $tree->{ItemSearchResponse}->{Items}->{Request});
$template->param(
  Results => {
    "TotalResults"  => $tree->{ItemSearchResponse}->{Items}->{TotalResults},
    "TotalPages"    => $tree->{ItemSearchResponse}->{Items}->{TotalPages},
    "Request"       => $tree->{ItemSearchResponse}->{Items}->{Request},
    "CarrentMinNum" => ($current_page - 1) * $entries_per_page + 1,
    "CarrentMaxNum" => $current_page * $entries_per_page < $total_entries
                       ? $current_page * $entries_per_page
                       : $total_entries,
  }
);
$template->param(
  SearchIndex => [
    "Blended", "Books", "Music", "MusicTracks", "Classical", "Video", "DVD", "VHS", "VideoGames", "Electronics", "Kitchen", "Toys", "Software"
  ]
);
$template->param(Paging => $paging_html);


print "Content-Type: text/html\n\n", $template->output;


20080321.tmpl(Template:20080313.tmplと同じ)

<!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>"<tmpl_var name=Request.ItemSearchRequest.Keywords>"の検索結果 - Amazon検索</title>
<style type="text/css">
/*&lt;![CDATA[*/
  body{
  	font-size: 90%;
  	line-height: 1.4;
  }
  img{
  	border: solid 1px #CC;
  }
  h1{
  	font-size: 120%;
  }
/*]]&gt;*/
</style>
</head>

<body>

<h1>Amazon検索</h1>

<form method="get" action="">
  <select name="SearchIndex">
    <tmpl_loop name=SearchIndex>
    <option value="<tmpl_var _>"><tmpl_var _></option>
    </tmpl_loop>
  </select>
  <input type="text" name="Keywords">
  <input type="submit">
</form>

<h2>"<tmpl_var name=Request.ItemSearchRequest.Keywords>"の検索結果</h2>
<p><tmpl_var name=Results.TotalResults>件中 <tmpl_var name=Results.CarrentMinNum> から  <tmpl_var name=Results.CarrentMaxNum> までを表示</p>
<p><tmpl_var name=Paging></p>
<table>
  <tmpl_loop name=Item>
  <tr>
    <td>
      <a href="http://www.amazon.co.jp/exec/obidos/ASIN/<TMPL_VAR name=ItemAttributes.ASIN>/tekiomo-22/ref=nosim/"><img src="http://images-jp.amazon.com/images/P/<tmpl_var name=ASIN>.09.TZZZZZZZ.jpg"></a>
    </td>
    <td>
      <h3><a href="http://www.amazon.co.jp/exec/obidos/ASIN/<TMPL_VAR name=ASIN>/tekiomo-22/ref=nosim/"><tmpl_var name=ItemAttributes.Title></a></h3>
    </td>
  </tr>
  </tmpl_loop>
</table>
<p><tmpl_var name=Paging></p>

</body>
</html>