package HTML::Widgets::Search;
use strict;
use DBI;
use URI;
use Carp;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %FIELD_OK $AUTOLOAD
%FIELD_READ_ONLY $DEBUG);
require Exporter;
require AutoLoader;
@ISA = qw(Exporter AutoLoader);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT = qw(
);
$VERSION = '0.07';
for my $attr (qw( query field_id start limit form_fields dbh DEBUG
current_start current_end spanish_date)) {
$FIELD_OK{$attr}++; # Los ponemos en ok
}
# Preloaded methods go here.
sub AUTOLOAD {
my $self=shift;
my $attr=$AUTOLOAD;
$attr=~s/.*:://;
return unless $attr=~/[^A-Z]/;
croak "Invalid attribute method: ->$attr()" unless $FIELD_OK{$attr};
if (@_) {
croak "Trying to write to read only field $attr"
if exists $FIELD_READ_ONLY{$attr};
$self->{$attr}=shift;
}
return $self->{$attr}; # Devolvemos el valor
}
sub new {
my $proto=shift;
my $class=ref($proto) || $proto;
my %arg=@_;# Cojemos los parametros
my $self={};
foreach (keys %arg) {
croak "Field invalid: $_ " unless exists $FIELD_OK{$_};
$self->{$_}=$arg{$_};
}
$self->{start}=$self->{form_fields}->{_start}
if exists $self->{form_fields}->{_start};
$self->{limit}=$self->{form_fields}->{_limit}
if exists $self->{form_fields}->{_limit}
and not exists $self->{limit};
delete $self->{form_fields}->{_start};
delete $self->{form_fields}->{_limit};
$self->{start}=0 if exists $self->{limit} and not exists $self->{start};
bless $self,$class;
$self->n_rows;
return $self;
}
sub header {
my $self=shift;
my ($text,$previous,$next)=@_;
$text=$self->current_start." - ".
$self->current_end.
'( '.$self->n_rows.')' unless defined $text;
$previous="previous" unless defined $previous;
$next = "next" unless defined $next;
my $ret = "
$text
";
if ($self->current_start > 1) {
$ret.="
".$self->prev(submit => "").
"
";
}
if ($self->current_end < $self->n_rows) {
$ret.="
".$self->next(submit => "").
"
";
}
return "$ret
";
}
sub prev {
my $self=shift;
return $self->prev_link(@_);
}
sub next {
my $self=shift;
return $self->next_link(@_);;
}
sub prev_link {
my $self=shift;
return $self->prev_link_post(@_) if scalar @_ >1;
my $url=(shift or "");
my $uri=URI->new($url);
my %args=%{$self->{form_fields}};
$args{_limit}=$self->{limit} if exists $self->{limit};
$args{_start}=$self->{start}-$self->{limit} if exists $self->{start};
$args{_start}=0 if $args{_start}<0;
$uri->query_form(%args);
return $uri->as_string();
}
sub href {
my $self=shift;
my %args=@_;
my $link_args;
my $uri;
if (exists $args{uri}) {
$uri=URI->new($args{uri});
$link_args=$args{args};
} else {
$uri=URI->new($ENV{REQUEST_URI});
$link_args=\%args
}
$link_args->{_limit}=$self->{limit} if exists $self->{limit};
$link_args->{_start}=$self->{start};
$uri->query_form(%$link_args);
return $uri->as_string();
}
sub form_args_html {
my $self=shift;
return '";
}
sub args_html {
my $self=shift;
my %arg=@_;
$arg{start}=$self->{start} unless exists $arg{start};
my $ret='';
foreach (keys %{$self->{form_fields}}) {
next unless exists $self->{form_fields}->{$_}
&&length $self->{form_fields}->{$_};
next unless /^[a-z0-9_]*$/i; # must be a valid SQL table field name
$ret.="{form_fields}->{$_}\">";
}
foreach (keys %{$arg{hidden}}) {
$ret.="{$_}\">\n"
}
$ret.='";
$ret.=" {limit}\">" if exists $self->{limit};
$ret.=$arg{submit} if exists $arg{submit};
return $ret;
}
sub html_form_fields {
my $self=shift;
return $self->args_html(
start => $self->{start}
);
}
sub next_link_post {
my $self=shift;
croak "Can't do next unless defined start and limit"
unless exists $self->{limit} and defined $self->{limit}
and exists $self->{start} and defined $self->{start};
return $self->form_args_html( @_,
start => $self->{start}+$self->{limit}
);
}
sub prev_link_post {
my $self=shift;
croak "Can't do prev unless defined start and limit"
unless exists $self->{limit} and defined $self->{limit}
and exists $self->{start} and defined $self->{start};
return $self->form_args_html( @_,
start=>$self->start - $self->limit);
}
sub next_link {
my $self=shift;
return $self->next_link_post(@_) if (scalar(@_) >1);
my $url=(shift or "");
my $uri=URI->new($url);
my %args=%{$self->{form_fields}};
$args{_limit}=$self->{limit} if exists $self->{limit};
$args{_start}=$self->{start}+$self->{limit}
if exists $self->{start};
$uri->query_form(%args);
return $uri->as_string();
}
sub n_rows {
my $self=shift;
return $self->{n_rows} if exists $self->{n_rows};
my $query=$self->{query};
$query=~s/\n//g;
$query=~s/(\s*SELECT)\s+(.*?)\s+(FROM .*$)/$1 count($2) $3/i;
$query=~s/order by.*//i;
$query =~ s/count\((.*?,.*?)\)/count(*)/;
warn $query if $DEBUG;
my $sth=$self->{dbh}->prepare($query) or die $DBI::errstr;
$sth->execute or die $DBI::errstr;
($self->{n_rows}) = $sth->fetchrow;
$sth->finish;
$self->{current_end}=$self->{start}+$self->{limit};
$self->{current_end}=$self->{n_rows}
if $self->{n_rows}<$self->{current_end};
$self->{current_start}=($self->{start} + 1);
return $self->{n_rows};
}
sub fetchrow_hashref {
my $self=shift;
if (defined $self->{sth}) {
return if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($self->{current} > ($self->{start}
+ $self->{limit}));
$self->{current}++;
return $self->{sth}->fetchrow_hashref;
}
my $query=$self->{query};
$query.=" LIMIT ".$self->{start}.",".$self->{limit}
if defined $self->{limit} and $self->{dbh}->{Driver}->{Name} eq "mysql";
warn $query if $DEBUG;
$self->{sth}=$self->{dbh}->prepare($query) or die $DBI::errstr;
$self->{sth}->execute or die $DBI::errstr;
my $row;
$self->{current}=0;
while ($row=$self->{sth}->fetchrow_hashref) {
last if $self->{dbh}->{Driver}->{Name} eq "mysql";
next if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($self->{current}++ < $self->{start});
last if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($self->{current} > ($self->{start}
+ $self->{limit}));
last if $self->{dbh}->{Driver}->{Name} ne "mysql";
}
return $row;
}
sub fetchrow {
my $self=shift;
if (defined $self->{sth}) {
return if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($self->{current} > ($self->{start}
+ $self->{limit}));
$self->{current}++;
return $self->{sth}->fetchrow;
}
my $query=$self->{query};
$query.=" LIMIT ".$self->{start}.",".$self->{limit}
if defined $self->{limit} and $self->{dbh}->{Driver}->{Name} eq "mysql";
warn $query if $DEBUG;
$self->{sth}=$self->{dbh}->prepare($query) or die $DBI::errstr;
$self->{sth}->execute or die ("\n$query\n\t$DBI::errstr");
my @row;
$self->{current}=0;
while (@row=$self->{sth}->fetchrow) {
last if $self->{dbh}->{Driver}->{Name} eq "mysql";
next if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($self->{current}++ < $self->{start});
last if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($self->{current} > ($self->{start} + $self->{limit}));
last if $self->{dbh}->{Driver}->{Name} ne "mysql";
}
return @row;
}
sub render_table {
my $self=shift;
my %arg=@_;
my $query=$self->{query};
$query.=" LIMIT ".$self->{start}.",".$self->{limit}
if defined $self->{limit} and $self->{dbh}->{Driver}->{Name} eq "mysql";
warn $query if $DEBUG;
my $sth=$self->{dbh}->prepare($query) or die $DBI::errstr;
my $html="";
$sth->execute or die $DBI::errstr;
my @row;
my $cont=0;
while (@row=$sth->fetchrow) {
next if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($cont++ < $self->{start});
last if $self->{dbh}->{Driver}->{Name} ne "mysql"
and ($cont > ($self->{start} + $self->{limit}));
$html.="
";
my $nfield=0;
foreach (@row) {
$nfield++;
next if $nfield==1 and defined $arg{link};
$_="" unless defined;
unless (defined $arg{link}) {
$html.="
";
}
$sth->finish;
return $html;
}
############ Draw data helper functions
sub draw {
my $self=shift;
my ($text)=@_;
return spanish_date($text)
if exists $self->{spanish_date} and $self->{spanish_date}
and $text=~/\d{4}-\d{2}-\d{2}/;
return $text;
}
sub spanish_date {
my ($date)=@_;
$date=~s/-0(\d)/-$1/g;
my ($any,$mes,$dia)=split /-/,$date;
return "$dia-$mes-$any";
}
# Autoload methods go after =cut, and are processed by the autosplit program.
1;
__END__
# Below is the stub of documentation for your module. You better edit it!
=head1 NAME
HTML::Widgets::Search - Perl module for building searches returning HTML
=head1 SYNOPSIS
<%perl>
use HTML::Widgets::Search;
my $search=HTML::Widgets::Search->new(
query => "SELECT idCustomer,name ".
" FROM customers WHERE name LIKE 'a%' ".
" ORDER BY name ",
field_id => "idCustomer",
limit => 10,
form_fields => \%ARGS,
dbh => $dbh
);
%perl>
<% $search->n_found %> customers found
<% $search->current_start %> to <% $search -> current_end %>
<% $search->head %>