Apache-Voodoo
view release on metacpan or search on metacpan
lib/Apache/Voodoo/Table.pm view on Meta::CPAN
}
if (@errors) {
Apache::Voodoo::Exception::RunTime::BadConfig->throw("Configuration Errors:\n\t".join("\n\t",@errors));
}
}
sub table {
my $self = shift;
if ($_[0]) {
$self->{'table'} = $_[0];
}
return $self->{'table'};
}
sub success {
my $self = shift;
return $self->{'success'};
}
sub edit_details {
my $self = shift;
# if there wasn't a successful edit, then there's no details :)
return unless $self->{'success'};
return $self->{'edit_details'} || [];
}
sub add_details {
my $self = shift;
# if there wasn't a successful add, then there's no details :)
return unless $self->{'success'};
return $self->{'add_details'} || [];
}
sub add_insert_callback {
my $self = shift;
my $sub_ref = shift;
push(@{$self->{'insert_callbacks'}},$sub_ref);
}
sub add_update_callback {
my $self = shift;
my $sub_ref = shift;
push(@{$self->{'update_callbacks'}},$sub_ref);
}
sub list_param_parser {
my $self = shift;
my $sub_ref = shift;
$self->{'list_param_parser'} = $sub_ref;
}
sub validate_add {
my $self = shift;
my $p = shift;
my $dbh = $p->{'dbh'};
my $params = $p->{'params'};
my $errors = {};
# call each of the insert callbacks
foreach (@{$self->{'insert_callbacks'}}) {
my $callback_errors = $_->($dbh,$params);
@{$errors}{keys %{$callback_errors}} = values %{$callback_errors};
}
# do all the normal parameter checking
my ($values,$e) = $self->{valid}->validate($params);
# copy the errors from the process_params
$errors = { %{$errors}, %{$e} } if ref($e) eq "HASH";
# check to see if the user supplied primary key (optional) is unique
if ($self->{'pkey_user_supplied'}) {
if ($params->{$self->{'pkey'}} =~ /$self->{'pkey_regexp'}/) {
my $res = $dbh->selectall_arrayref("
SELECT 1
FROM $self->{'table'}
WHERE $self->{'pkey'} = ?",
undef,
$params->{$self->{'pkey'}} );
if ($res->[0]->[0] == 1) {
$errors->{'DUP_'.$self->{'pkey'}} = 1;
}
}
else {
$errors->{'BAD_'.$self->{'pkey'}} = 1;
}
}
# check each unique column constraint
foreach (@{$self->{'unique'}}) {
my $res = $dbh->selectall_arrayref("
SELECT 1
FROM $self->{'table'}
WHERE $_ = ?",
undef,
$values->{$_});
if ($res->[0]->[0] == 1) {
$errors->{"DUP_$_"} = 1;
}
}
return ($values,$errors);
}
sub validate_edit {
my $self = shift;
my $p = shift;
my $dbh = $p->{'dbh'};
my $params = $p->{'params'};
unless ($params->{$self->{'pkey'}} =~ /$self->{'pkey_regexp'}/) {
return $self->display_error("Invalid ID");
}
my $errors = {};
# call each of the update callbacks
foreach (@{$self->{'update_callbacks'}}) {
# call back should return a list of error strings
my $callback_errors = $_->($dbh,$params);
@{$errors}{keys %{$callback_errors}} = values %{$callback_errors};
}
# run the standard error checks
my ($values,$e) = $self->{valid}->validate($params);
# copy the errors from the process_params
$errors = { %{$errors}, %{$e} } if ref($e) eq "HASH";
# check all the unique columns
foreach (@{$self->{'unique'}}) {
my $res = $dbh->selectall_arrayref("
SELECT 1
FROM $self->{'table'}
WHERE $_ = ? AND $self->{'pkey'} != ?",
undef,
$values->{$_},
$params->{$self->{'pkey'}});
if ($res->[0]->[0] == 1) {
$errors->{"DUP_$_"} = 1;
}
}
return $values,$errors;
}
sub add {
my $self = shift;
my $p = shift;
my $dbh = $p->{'dbh'};
my $params = $p->{'params'};
my $errors = {};
$self->{'success'} = 0;
$self->{'add_details'} = [];
if ($params->{'cm'} eq "add") {
my ($values,$errors) = $self->validate_add($p);
if (scalar keys %{$errors}) {
$errors->{'HAS_ERRORS'} = 1;
# copy values back into form
foreach (keys(%{$values})) {
$errors->{$_} = $values->{$_};
}
}
else {
# copy clean dates,times into params for insertion
foreach (@{$self->{'dates'}},@{$self->{'times'}}) {
$values->{$_->{'name'}} = $values->{$_->{'name'}."_CLEAN"};
}
my $c = join(",", @{$self->{'columns'}}); # the column names
my $q = join(",",map {"?"} @{$self->{'columns'}}); # the ? mark placeholders
my @v = map { $values->{$_} } @{$self->{'columns'}}; # and the values
# store the values as they went into the db here incase the caller wants to
# use them for something.
foreach (@{$self->{'columns'}}) {
push(@{$self->{'add_details'}},[$_,'',$values->{$_}]);
}
if ($self->{'pkey_user_supplied'}) {
$c .= ",".$self->{'pkey'};
$q .= ",?";
push(@v,$params->{$self->{'pkey'}});
}
my $insert_statement = "INSERT INTO $self->{'table'} ($c) VALUES ($q)";
$dbh->do($insert_statement, undef, @v);
$self->{'success'} = 1;
return 1;
}
}
# populate drop downs (also maintaining previous state).
foreach (@{$self->{'references'}}) {
my $query = "SELECT
$_->{'pkey'},
$_->{'slabel'}
FROM
$_->{'table'}
$_->{'sextra'}";
my $res = $dbh->selectall_arrayref($query);
$errors->{$_->{'fkey'}} = $self->prep_select($res,$errors->{$_->{'fkey'}} || $_->{'sdefault'});
}
# If we get here the user is just loading the page
# for the first time or had errors.
return $errors;
}
sub edit {
my $self = shift;
my $p = shift;
my $additional_constraint = shift;
$self->{'success'} = 0;
$self->{'edit_details'} = [];
my $dbh = $p->{'dbh'};
my $params = $p->{'params'};
# make sure our additional constraint won't break the sql
$additional_constraint =~ s/^\s*(where|and|or)\s+//go;
if (length($additional_constraint)) {
$additional_constraint = "AND $additional_constraint";
}
unless ($params->{$self->{'pkey'}} =~ /$self->{'pkey_regexp'}/) {
return $self->display_error("Invalid ID");
}
# find the record to be updated
my $res = $dbh->selectall_arrayref("
SELECT ".
join(",",@{$self->{'columns'}}). "
FROM
$self->{'table'}
WHERE
$self->{'pkey'} = ?
$additional_constraint",
undef,
$params->{$self->{'pkey'}});
unless (defined($res->[0])) {
return $self->display_error("No record with that ID found");
}
my %original_values;
for (my $i=0; $i <= $#{$self->{'columns'}}; $i++) {
$original_values{$self->{'columns'}->[$i]} = $res->[0]->[$i];
}
my $errors = {};
if ($params->{'cm'} eq "update") {
my ($values,$errors) = $self->validate_edit($p);
if (scalar keys %{$errors}) {
$errors->{'has_errors'} = 1;
# copy values into template
$errors->{$self->{'pkey'}} = $params->{$self->{'pkey'}};
foreach (keys(%{$values})) {
$errors->{$_} = $values->{$_};
}
}
else {
# copy clean dates,times into params for insertion
foreach (@{$self->{'dates'}},@{$self->{'times'}}) {
$values->{$_->{'name'}} = $values->{$_->{'name'}."_CLEAN"};
}
# let's figure out what they changed so caller can do something with that info if they want
foreach (@{$self->{'columns'}}) {
if ($values->{$_} ne $original_values{$_}) {
push(@{$self->{'edit_details'}},[$_,$original_values{$_},$values->{$_}]);
}
}
my $update_statement = "
UPDATE
$self->{'table'}
SET ".
join("=?,",@{$self->{'columns'}})."=?
WHERE
$self->{'pkey'} = ?
$additional_constraint";
# $self->debug($update_statement);
# $self->debug((map {$values->{$_}} @{$self->{'columns'}}),$params->{$self->{'pkey'}});
$dbh->do($update_statement,
undef,
(map { $values->{$_} } @{$self->{'columns'}}),
$params->{$self->{'pkey'}});
$self->{'success'} = 1;
return 1;
}
}
else {
foreach (@{$self->{'columns'}}) {
$errors->{$_} = $original_values{$_};
}
$errors->{$self->{'pkey'}} = $params->{$self->{'pkey'}};
# pretty up dates
foreach (@{$self->{'dates'}}) {
$errors->{$_->{'name'}} = $self->sql_to_date($errors->{$_->{'name'}});
}
# pretty up times
foreach (@{$self->{'times'}}) {
$errors->{$_->{'name'}} = $self->sql_to_time($errors->{$_->{'name'}});
}
}
( run in 0.505 second using v1.01-cache-2.11-cpan-39bf76dae61 )