我(仍)在学习Perl的Catalyst框架。而且我需要翻阅一长串书。我不知道该使用什么来分页以及如何使用它。其次,如果我想将“ page = 1”参数传递给我的列表方法(现在以它的形式),则传递的值将不正确。如果我将Args的数量修改为1,则它会抱怨找不到页面。
这些是我的文件:
Book.pm (ORM文件)
use utf8;
package Library::Schema::Result::Books;
use strict;
use warnings;
use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';
__PACKAGE__->load_components("InflateColumn::DateTime");
__PACKAGE__->table("books");
__PACKAGE__->add_columns(
"id",
{
data_type => "uuid",
default_value => \"uuid_generate_v4()",
is_nullable => 0,
size => 16,
},
"title",
{ data_type => "varchar", is_nullable => 0, size => 128 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("uk_books", ["title"]);
__PACKAGE__->meta->make_immutable;
1;
Book.pm (控制器)
package Library::Controller::Book;
use Moose;
use namespace::autoclean;
use utf8;
use Data::Validate::UUID qw(is_uuid);
BEGIN { extends 'Catalyst::Controller'; }
sub base :Chained('/'): PathPart('book'): CaptureArgs(0) {
my ($self, $c) = @_;
$c->stash(books_rs => $c->model('DB::Books'));
$c->stash(books => [$c->stash->{books_rs}->search(
{},
{order_by => 'title ASC'})]
);
}
sub list :Chained('base'): PathPart('list'): Args(0) {
my ($self, $c) = @_;
$c->stash(template => 'book/list.tt2');
}
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
return $c->res->redirect(
$c->uri_for($c->controller('Book')->action_for('list'))
);
}
sub book :Chained('base'): PathPart(''): CaptureArgs(1) {
my ($self, $c, $bookid) = @_;
if(!is_uuid(uc($bookid))) {
die "Invalid book ID.";
}
my $book = $c->stash->{books_rs}->find(
{ id => $bookid },
{ key => 'primary' }
);
die "No such user" if(!$book);
$c->stash(book => $book);
}
sub add :Chained('base'): PathPart('add'): Args(0) {
my ($self, $c) = @_;
if(lc $c->req->method eq 'post') {
my $params = $c->req->params;
my $books_rs = $c->stash->{books_rs};
my $newbook = $books_rs->create({
title => $params->{newBookTitle},
});
return $c->res->redirect(
$c->uri_for($c->controller('Book')->action_for('list')
));
}
}
sub edit :Chained('book') :PathPart('edit'): Args(0) {
my ($self, $c) = @_;
if(lc $c->req->method eq 'post') {
my $params = $c->req->params;
my $book = $c->stash->{book};
$book->update({
title => $params->{title},
});
return $c->res->redirect( $c->uri_for(
$c->controller('Book')->action_for('list'),
[ $book->id ]
));
}
}
sub remove :Chained('book'): PathPart('remove'): Args() {
my ($self, $c) = @_;
my $book = $c->stash->{book};
$book->delete();
return $c->res->redirect(
$c->uri_for($c->controller('Book')->action_for('list'))
);
}
__PACKAGE__->meta->make_immutable;
1;
以及我的 books / list.tt 文件中的相关部分:
<table>
<thead>
<tr>
<th></th>
<th>Book title</th>
</tr>
</thead>
<tbody>
[% FOREACH book IN books -%]
<tr>
<td>
<a href="[%- c.uri_for(c.controller('Book').action_for('remove'), [book.id]) %]">
<img src="../../images/trash.png" width="22" height="22">
</a>
</td>
<td>[% book.title %]</td>
</tr>
[% END -%]
</tbody>
</table>
答案 0 :(得分:0)
要使其正常工作,您需要做两件事。总体而言,这很简单。 DBIC Cookbook中对此进行了说明。
您的list
方法只列出了未分页的完整图书清单,这些清单藏在您的base
链接方法中。现在,您需要添加代码以采用URL参数并减少列表。
sub list :Chained('base'): PathPart('list'): Args(0) {
my ($self, $c) = @_;
if (my $page = $c->req->params->{page}) {
# TODO: validate $page
my $rs = $c->stash->{books};
$c->stash->{books} = $rs->search(undef, {
page => $page,
rows => 10, # or how many you want
});
}
$c->stash(template => 'book/list.tt2');
}
此代码将用一个新的结果集替换保存的结果集,该结果集已附加LIMIT
。请记住,结果集可以链式堆叠,因此,每将一个新的->search
都称为结果集对象,就会返回一个进一步深入的新结果集。直到稍后在模板中使用SQL时,才在列表上下文中使用SQL,这意味着需要调用->all
。
无需为显示较小列表而对模板进行任何更改。
但是,您可能希望控制分页。您可以使用Data::Page对象来实现。您的结果集可以方便地为您提供此结果。但是,这要付出额外的COUNT
查询的代价。如果您对正在发生的事情感兴趣,请打开DBIC_TRACE=1
环境变量以查看在后台运行的查询。
在您刚刚添加上述代码的list
方法中,也隐藏了寻呼机。
my $rs = $c->stash->{books};
$c->stash->{books} = $rs->search(undef, {
page => $page,
rows => 10, # or how many you want
});
$c->stash->{pager} = $rs->pager;
现在,我们需要在模板中显示一些控件。我不会全部显示,只给您一个想法。由于我们仍支持完整列表,因此只有在有寻呼机的情况下,我们才能显示控件。
<table>
[%# ... %]
<tbody>
[% FOREACH book IN books -%]
<tr>
[%# ... %]
</tr>
[% END -%]
</tbody>
</table>
[% IF pager %]
<ul>
<li><a href="?page=[% pager.first_page %]">First page</a></li>
</ul>
[% END %]
这里不需要使用c.uri_for
,因为我们要做的就是添加URL参数。用户的浏览器足够聪明,可以使仅包含参数的相对URL指向已经存在的相同内容。因此,如果用户正在查看https://example.org/list?page=2
,则单击首页链接?page=1
实际上会将他们带到https://example.org/list?page=1
。
答案 1 :(得分:0)
我设法摆脱了该非页面错误:
sub list :Chained('base'): PathPart('list'): Args(0) {
my ($self, $c) = @_;
if (my $page = $c->req->params->{page}) {
my $rs = $c->stash->{books_rs}->search({}, {
page => $page,
rows => 5,
});
$c->stash->{books_rs} = $rs;
$c->stash->{pager} = $rs->pager;
}
$c->stash(template => 'book/list.tt2');
}
,但仍显示所有书籍。使用 page 参数传递的值对结果集没有影响。