2 package POE::Component::IRC::Plugin::NoPaste::Pager;
8 use Hash::Util qw(lock_keys);
13 my $pager = Pager->new(
17 sql => q{SELECT foo, bar FROM foo WHERE bar=? AND baz=?},
18 placeholder => [100, 200],
24 # $begin: 表示を開始する項目の番號(0オリジン)
26 # $code_show: 表面的には、show_contentで指定された關數(内部的には違ふ)
27 my ($begin, $length, $code_show) = @_;
28 for ($begin .. ($begin + $length - 1)) {
29 $code_show->("Item [$_]");
34 # fetchがSQL文であるなら、countを省略すれば
35 # 自動的にSELECT COUNT(*)文をfetchのSQLから生成する。
37 sql => q{SELECT COUNT(*) FROM foo WHERE bar=? AND baz=?},
38 placeholder => [100, 200],
47 page_to_show => 2, # 表示したいページ(1オリジン); デフォルトは1
48 pagenums_limit => 10, # 各ページへのリンクの最大表示個數; デフォルトは10
49 items_per_page => 20, # ページ毎の項目の最大表示數; デフォルトは20
56 # pagelink_begin: 各ページへのリンクの開始ページ番號
57 # pagelink_end: 各ページへのリンクの終了ページ番號(この番號も含む)
59 print "page: $meta{page}/$meta{last_page}; total: $meta{total}\n";
63 # fetchがSQL文なら、$_[0]はfetchrow_hashrefで得られたハッシュ。
64 # CODEなら、そのCODEの中から明示的に呼ばれなければならない。
65 print "item: $_[0]\n";
67 # 項目が一つも無い時に呼ばれる關數。省略可。
77 my ($class, %args) = @_;
79 my $fetch = $args{fetch};
80 if (!isa $fetch, 'HASH') {
81 croak "Arg{fetch} is not a hashref";
83 if (defined $fetch->{sql}) {
84 $fetch->{dbh} or croak "Arg{fetch} has a sql, but not dbh";
85 $fetch->{code} and croak "Arg{fetch} has both of sql and code";
86 # FIXME: LIMITが付いてゐたらcroak
88 elsif (defined $fetch->{code}) {
89 (isa $fetch->{code}, 'CODE') or croak "Arg{fetch}{code} is not a coderef: ".$fetch->{code};
90 $fetch->{sql} and croak "Arg{fetch} has both of sql and code";
93 my $count = $args{count};
94 if (!defined $count) {
95 if (defined $fetch->{sql}) {
97 (my $sql = $fetch->{sql}) =~ s/^\s*select\s+(.+?)\s+from/select count(*) from/i;
98 $count = $args{count} = {};
100 $count->{placeholder} = $fetch->{placeholder} if $fetch->{placeholder};
101 $count->{dbh} = $fetch->{dbh};
104 croak "Arg{count} cannot be omitted when the Arg{fetch} is not a SQL";
107 elsif (!isa $count, 'HASH') {
108 croak "Arg{count} is not a hashref";
110 # FIXME: $args{count}のsanity checkを(もっと)
112 # FIXME: 以下の三つの變數をsanity check
113 $args{page_to_show} ||= 1;
114 $args{pagenums_limit} ||= 10;
115 $args{items_per_page} ||= 20;
117 foreach my $key (qw/show_meta show_content/) {
118 if (!defined $args{$key}) {
119 croak "Missing Arg{$key}";
121 elsif (!isa $args{$key}, 'CODE') {
122 croak "Arg{$key} is not a coderef: $args{$key}";
126 if (defined $args{no_content} and
127 !isa $args{no_content}, 'CODE') {
128 croak "Arg{no_content} is not a coderef: $args{no_content}";
130 $args{no_content} ||= undef;
132 my $this = bless \%args => $class;
139 my $floor = int($val);
140 $floor == $val ? $floor : $floor + 1;
146 $min = $_ if $min > $_;
154 $max = $_ if $max < $_;
163 if (defined $this->{count}{sql}) {
165 $count = $this->{count}{dbh}->selectrow_array(
166 $this->{count}{sql}, undef, @{$this->{count}{placeholder} || []});
168 throw Error::Simple "Failed to do count by sql: $_[0]";
173 $count = $this->{count}{code}->();
175 throw Error::Simple "Failed to do count by code: $_[0]";
180 my $last_page = max(1, ceil($count / $this->{items_per_page}));
181 my $page = min($this->{page_to_show}, $last_page);
182 my $pagelink_begin = max(1, int($page - $this->{pagenums_limit} / 2));
183 my $pagelink_end = min($last_page, $pagelink_begin + $this->{pagenums_limit} - 1);
186 $this->{show_meta}->(
189 last_page => $last_page,
190 pagelink_begin => $pagelink_begin,
191 pagelink_end => $pagelink_end);
194 my $fetch_begin = ($page - 1) * $this->{items_per_page};
195 my $fetch_length = min($count - $fetch_begin,
196 $this->{items_per_page});
197 if (defined $this->{fetch}{sql}) {
199 # FIXME: これより増しなLIMIT生成方法を
200 my $sql = $this->{fetch}{sql} . " LIMIT $fetch_begin, $fetch_length";
202 my $sth = $this->{fetch}{dbh}->prepare($sql);
203 $sth->execute(@{$this->{fetch}{placeholder} || []});
204 while ($_ = $sth->fetchrow_hashref) {
205 $this->{show_content}->($_);
207 if ($sth->rows == 0) {
208 $this->{no_content} and
209 $this->{no_content}->();
212 throw Error::Simple "Failed to do fetch by sql: $_[0]";
216 # $fetch_length囘呼ばれたかどうかをチェックする
217 my $called_count = 0;
218 my $checked_show = sub {
220 goto &{$this->{show_content}};
223 $this->{fetch}{code}->(
224 $fetch_begin, $fetch_length, $checked_show);
226 throw Error::Simple "Failed to do fetch by code: $_[0]";
228 if ($called_count != $fetch_length) {
229 carp "Fetch coderef didn't call show_content exactly $fetch_length times (call \$length($fetch_length) times)";
231 if ($fetch_length == 0) {
232 $this->{no_content} and
233 $this->{no_content}->();