Commit f6fc02e5 authored by Max Kanat-Alexander's avatar Max Kanat-Alexander

Bug 545524: New Hook: object_validators

r=mkanat, a=mkanat (module owner)
parent 80477beb
...@@ -123,8 +123,6 @@ use constant REQUIRED_CREATE_FIELDS => qw( ...@@ -123,8 +123,6 @@ use constant REQUIRED_CREATE_FIELDS => qw(
# There are also other, more complex validators that are called # There are also other, more complex validators that are called
# from run_create_validators. # from run_create_validators.
sub VALIDATORS { sub VALIDATORS {
my $cache = Bugzilla->request_cache;
return $cache->{bug_validators} if defined $cache->{bug_validators};
my $validators = { my $validators = {
alias => \&_check_alias, alias => \&_check_alias,
...@@ -167,8 +165,7 @@ sub VALIDATORS { ...@@ -167,8 +165,7 @@ sub VALIDATORS {
$validators->{$field->name} = $validator; $validators->{$field->name} = $validator;
} }
$cache->{bug_validators} = $validators; return $validators;
return $cache->{bug_validators};
}; };
use constant UPDATE_VALIDATORS => { use constant UPDATE_VALIDATORS => {
......
...@@ -675,6 +675,32 @@ L<Bugzilla::Object/update> returns. ...@@ -675,6 +675,32 @@ L<Bugzilla::Object/update> returns.
=back =back
=head2 object_validators
Allows you to add new items to L<Bugzilla::Object/VALIDATORS> for
particular classes.
Params:
=over
=item C<class>
The name of the class that C<VALIDATORS> was called on. You can check this
like C<< if ($class->isa('Some::Class')) >> in your code, to add
validators only for certain classes
=item C<validators>
A hashref, where the keys are database columns and the values are subroutine
references. You can add new validators or modify existing ones. If you modify
an existing one, you should remember to call the original validator
inside of your modified validator. (This way, several extensions can all
modify the same validator.)
=back
=head2 page_before_template =head2 page_before_template
This is a simple way to add your own pages to Bugzilla. This hooks C<page.cgi>, This is a simple way to add your own pages to Bugzilla. This hooks C<page.cgi>,
......
...@@ -288,7 +288,7 @@ sub set { ...@@ -288,7 +288,7 @@ sub set {
{ object => $self, field => $field, { object => $self, field => $field,
value => $value }); value => $value });
my %validators = (%{$self->VALIDATORS}, %{$self->UPDATE_VALIDATORS}); my %validators = (%{$self->_get_validators}, %{$self->UPDATE_VALIDATORS});
if (exists $validators{$field}) { if (exists $validators{$field}) {
my $validator = $validators{$field}; my $validator = $validators{$field};
$value = $self->$validator($value, $field); $value = $self->$validator($value, $field);
...@@ -430,7 +430,7 @@ sub check_required_create_fields { ...@@ -430,7 +430,7 @@ sub check_required_create_fields {
sub run_create_validators { sub run_create_validators {
my ($class, $params) = @_; my ($class, $params) = @_;
my $validators = $class->VALIDATORS; my $validators = $class->_get_validators;
my %field_values; my %field_values;
# We do the sort just to make sure that validation always # We do the sort just to make sure that validation always
...@@ -487,6 +487,27 @@ sub get_all { ...@@ -487,6 +487,27 @@ sub get_all {
sub check_boolean { return $_[1] ? 1 : 0 } sub check_boolean { return $_[1] ? 1 : 0 }
# For some clases, VALIDATORS takes time to generate, so we cache it. Also,
# this allows the object_validators hook to only run once per request,
# instead of every time we call set() on a class of objects.
#
# This method is intentionally private and should only be called by
# Bugzilla::Object.
sub _get_validators {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $cache = Bugzilla->request_cache;
my $cache_key = "object_${class}_validators";
return $cache->{$cache_key} if $cache->{$cache_key};
# We copy this into a hash so that the hook doesn't modify the constant.
# (That could be bad in mod_perl.)
my %validators = %{ $invocant->VALIDATORS };
Bugzilla::Hook::process('object_validators',
{ class => $class, validators => \%validators });
$cache->{$cache_key} = \%validators;
return $cache->{$cache_key};
}
1; 1;
__END__ __END__
......
...@@ -25,6 +25,7 @@ use strict; ...@@ -25,6 +25,7 @@ use strict;
use base qw(Bugzilla::Extension); use base qw(Bugzilla::Extension);
use Bugzilla::Constants; use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Group; use Bugzilla::Group;
use Bugzilla::User; use Bugzilla::User;
use Bugzilla::Util qw(diff_arrays html_quote); use Bugzilla::Util qw(diff_arrays html_quote);
...@@ -376,6 +377,45 @@ sub object_end_of_update { ...@@ -376,6 +377,45 @@ sub object_end_of_update {
} }
} }
sub object_validators {
my ($self, $args) = @_;
my ($class, $validators) = @$args{qw(class validators)};
if ($class->isa('Bugzilla::Bug')) {
# This is an example of adding a new validator.
# See the _check_example subroutine below.
$validators->{example} = \&_check_example;
# This is an example of overriding an existing validator.
# See the check_short_desc validator below.
my $original = $validators->{short_desc};
$validators->{short_desc} = sub { _check_short_desc($original, @_) };
}
}
sub _check_example {
my ($invocant, $value, $field) = @_;
warn "I was called to validate the value of $field.";
warn "The value of $field that I was passed in is: $value";
# Make the value always be 1.
my $fixed_value = 1;
return $fixed_value;
}
sub _check_short_desc {
my $original = shift;
my $invocant = shift;
my $value = $invocant->$original(@_);
if ($value !~ /example/i) {
# Uncomment this line to make Bugzilla throw an error every time
# you try to file a bug or update a bug without the word "example"
# in the summary.
#ThrowUserError('example_short_desc_invalid');
}
return $value;
}
sub page_before_template { sub page_before_template {
my ($self, $args) = @_; my ($self, $args) = @_;
......
...@@ -9,4 +9,7 @@ ...@@ -9,4 +9,7 @@
[% IF error == "example_my_error" %] [% IF error == "example_my_error" %]
[% title = "Example Error Title" %] [% title = "Example Error Title" %]
This is the error message! It contains <em>some html</em>. This is the error message! It contains <em>some html</em>.
[% ELSIF error == "example_short_desc_invalid" %]
[% title = "Bad Summary" %]
The Summary must contain the word "example".
[% END %] [% END %]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment