Как разбивать длинные списки на страницы - PullRequest
0 голосов
/ 08 октября 2018

Я (все еще) изучаю Catalyst Framework для Perl.И мне нужно разбить на страницы длинный список книг.Что я не знаю, что использовать для нумерации страниц и как его использовать.Во-вторых, если я хочу передать параметр "page = 1" в мой метод списка (в его форме сейчас), переданное значение не применяется.Если я изменю количество аргументов на 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>

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Мне удалось избавиться от этой невыгружаемой ошибки:

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 , не влияет на набор результатов.

0 голосов
/ 08 октября 2018

Есть две вещи, которые вам нужно сделать, чтобы заставить это работать.В целом, это довольно просто.Он описан в 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 не запускается до тех пор, пока позже в вашем шаблоне, где вы используете его в контексте списка, что подразумевает вызов ->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;

Template

Теперь нам нужно отобразить некоторые элементы управления в шаблоне.Я не буду показывать все из них, но только дать вам представление.Поскольку мы по-прежнему поддерживаем полный список, мы можем отображать элементы управления только при наличии пейджера.

<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.

...