Top > MyPage
 

DBIx::Class::ResultSetのページャ

DBIxでsearch

Catalystでアプリケーションを組んで、その中でDBIx::ClassをつかってDBとやり取りをしているとする。

(Catalystのセットアップについては長くなるので割愛させていただく。)

このアプリケーションとやり取りしているDBには、CDというテーブルがあり、その中のカラムはidtitleartistcontentの4つであるとする。

このテーブルからartistがZARDであるデータを取り出したい場合は、例えば次に挙げる例のような書き方をすることになる。

my $rs = $c->model('PGTDB::CD')->search({ artist => 'ZARD' });

上記のPGTDB::CDは、テーブルCDに対応したスキーマクラスである。おそらく通常は、このように複数のデータが返ってくる可能性があるような場合は配列で受けるのだが(私はいつも配列で受けていた)、上の例ではスカラで受け取っている。このようにすると$rsにはDBIx::Class::ResultSetのオブジェクトが入っている。

@rsとして受け取った場合は、

$c->stash->{'searched'} = \@rs;

として配列のリファレンスを渡して、テンプレートに次のような書き方をすることで、一つ一つ取り出すことが出来る。

[% FOREACH cd IN searched %]

title is [% cd.title %] artist is [% cd.artist %] <br>

[% END %]

$rsとして受け取った場合は次のようにすることで同様になる。

$c->stash->{'searched'} = $rs;

オブジェクトを同様に渡して、テンプレートには次のように書く。

[% WHILE (cd = searched.next) %]

title is [% cd.title %] artist is [% cd.artist %] <br>

[% END %]

ResultSetのpagerメソッド

ResultSetにはpagerというメソッドがあり、これを用いると、Data::Pageのオブジェクトを得ることが出来る。このオブジェクトをテンプレートに渡すことでページャを実装することが出来る。

pagerメソッドを使う。

先の検索の例を少し変えて説明する。

ページャを表示するには、「1ページに表示する要素数」と「現在のページ番号」が必須である。

「1ページに表示する要素数」は設定ファイルで固定するとするとして、「現在のページ番号」はブラウザから送信されたリクエストから得る必要がある。


    my $entries_per_page = 10;
    
    「1ページに表示する要素数」10固定ということにする。


    my $current_page = $c->request->param('current_page');
    $current_page ||= 1;
    
    リクエストにページ番号が含まれていなかった場合(最初)は「1」にする。

先の例では、artistがZARDであるデータを取り出していたが、今度はそのような条件を入れずに検索することにする。ただし、現在表示するページに対応したデータだけ取り出したい。

$rs = $c->model('PGTDB::CD')->search({ },
                            {
                                page     => $current_page,
                                rows     => $entries_per_page,
                            });

今度の例では、第一引数が空であるので、このテーブルの全ての行が対象になる。第二引数で、pageに「現在のページ番号」を、rowsに「1ページに表示する要素数」を指定しているのが分かる。これで表示するページに該当するデータだけが取り出されて、オブジェクトとして$rsに格納される。

それから次のように、pager()メソッドでData::Pageオブジェクトを取り出して、テンプレートに渡す。テンプレート側では「pager」というキーで受け取ることが出来る。

$c->stash->{pager} = $rs->pager();

次に示すのが、テンプレートでページャを表示する部分の例である。urlの部分が長くなったため改行しているが、本当は改行はない事に注意。また、entries_per_pageはプログラム側で10固定としているので、本当は不要である。この部分を可変として作る場合に必要となってくる。

[% IF pager%]
  Total [% pager.total_entries %] items.
  [%IF pager.previous_page %]
    <a href="[% Catalyst.uri_for('/pagetest/') %]
    ?entries_per_page=[% pager.entries_per_page %];
    current_page=[% pager.previous_page %];">&nbsp;<&nbsp;</a>
  [% END %]
  [% FOREACH num=[pager.first_page .. pager.last_page] %]
      [% IF num == pager.current_page %][% num %]
      [% ELSE %]
      <a href="[% Catalyst.uri_for('/pagetest/') %]?entries_per_page=[% pager.entries_per_page %];current_page=[% num %];">[% num %]</a>
      [% END %]
  [% END %]
  [%IF pager.next_page%]
    <a href="[% Catalyst.uri_for('/pagetest/') %]?entries_per_page=[% pager.entries_per_page %];current_page=[% pager.next_page %];">&nbsp;>&nbsp;</a>
  [% END %]
[% END %]

上の例で使用しているData::Pageのメソッドの説明をする。

total_entries

・表示されていない分も合わせた全ての要素数を返す。

previous_page

・現在表示されているページの一つ前のページ番号を返す。

entries_per_page

・1ページあたりに表示させる要素数を返す。

first_page

・最初のページの番号を返す。つまり、1を返す。

last_page

・総ページ数を返す。要素数で変化する。

current_page

・現在表示しているページの番号を返す。

例えば、CDテーブルに情報が50件あったとすると、この部分はこのように表示される。


Total 50 items.
1          2345>

        

このように、ResultSetのpager()を用いると、検索結果から、ページャのオブジェクトを生成できるので、非常に手軽である。検索結果のオブジェクトとページャのオブジェクトをテンプレートに渡して、表示させればよいからである。

ただし、Data::Pageの提供する機能は簡素なものであるので、上の例のようなシンプルなページャとなってしまう。

例えば、次のような点が不便である。

  • ナビゲーションのページ番号の表示数を制限できない。
  • 「次のページへ」、「前のページへ」はあるが「次のページ群へ」、「前のページ群へ」はできない。

要素数がそれほど多くはならないと予想される場合は、これで十分と思われるが、多くなると予想される場合は、使わない方が良いかと思われる。