package Data::Page::Flexible; use warnings; use strict; use Carp; use POSIX qw(ceil floor); use base qw(Class::Accessor::Chained::Fast Data::Page); use version; our $VERSION = qv('0.0.1'); __PACKAGE__->mk_accessors(qw(flexibility)); sub new { my ($class, $arg_ref) = @_; my $self = {}; croak("total_entries and entries_per_page must be supplied") unless defined $arg_ref->{'total_entries'} && defined $arg_ref->{'entries_per_page'}; bless($self, $class); # flexibility can be 0, which is false, so can't use ||-assignment my $flexibility = exists $arg_ref->{flexibility} ? $arg_ref->{flexibility} : floor($arg_ref->{entries_per_page} / 2); $self->_flexibility_accessor( $flexibility ); $self->_total_entries_accessor( $arg_ref->{total_entries} ); $self->_current_page_accessor( $arg_ref->{current_page} || 1 ); $self->_entries_per_page_accessor( $arg_ref->{entries_per_page} ); $self->_entries_per_page_accessor( $self->_get_flexible_epp() ); return $self; } # Calculate the entries_per_page (expected_epp) within the limits of the flexibility sub _get_flexible_epp { my ($self) = @_; my $flexibility = $self->flexibility(); my $total_entries = $self->total_entries(); my $entries_per_page = $self->entries_per_page(); return $entries_per_page if $flexibility == 0 || $total_entries == 0; return $entries_per_page if $total_entries < $entries_per_page; my $pages = ceil($total_entries / $entries_per_page); my $expected_epp = $total_entries / $pages; ENTRIES: while ( $expected_epp < $entries_per_page ) { $pages--; $pages = 1 if $pages < 1; $expected_epp = $total_entries / $pages; if ( $expected_epp > $entries_per_page + $flexibility ) { $expected_epp = $entries_per_page; last ENTRIES; } } return ceil($expected_epp); } sub total_entries { my $self = shift; if ( @_ ) { my $accessor = $self->_total_entries_accessor(@_); $self->_entries_per_page_accessor( $self->_get_flexible_epp() ); return $accessor; } return $self->_total_entries_accessor(); } sub entries_per_page { my $self = shift; my $entries_per_page = $_[0]; if ( @_ ) { croak(sprintf('There must be at least one entry per page. %d is too small.', $entries_per_page)) if $entries_per_page < 1; $self->_entries_per_page_accessor(@_); return $self->_entries_per_page_accessor( $self->_get_flexible_epp() ); } return $self->_entries_per_page_accessor(); } sub flexibility { my $self = shift; if ( @_ ) { my $accessor = $self->_flexibility_accessor(@_); $self->_entries_per_page_accessor( $self->_get_flexible_epp() ); return $accessor; } return $self->_flexibility_accessor(); } 1;