]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 545524: New Hook: object_validators
authorMax Kanat-Alexander <mkanat@bugzilla.org>
Thu, 11 Feb 2010 00:00:32 +0000 (16:00 -0800)
committerMax Kanat-Alexander <mkanat@bugzilla.org>
Thu, 11 Feb 2010 00:00:32 +0000 (16:00 -0800)
r=mkanat, a=mkanat (module owner)

Bugzilla/Bug.pm
Bugzilla/Hook.pm
Bugzilla/Object.pm
extensions/Example/Extension.pm
extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl

index 37df3070739abb65ab6f151d905f5c7ec215b1c5..336b9cfe10573f28f4ddff5ae47c514eb269796d 100644 (file)
@@ -123,8 +123,6 @@ use constant REQUIRED_CREATE_FIELDS => qw(
 # There are also other, more complex validators that are called
 # from run_create_validators.
 sub VALIDATORS {
-    my $cache = Bugzilla->request_cache;
-    return $cache->{bug_validators} if defined $cache->{bug_validators};
 
     my $validators = {
         alias          => \&_check_alias,
@@ -167,8 +165,7 @@ sub VALIDATORS {
         $validators->{$field->name} = $validator;
     }
 
-    $cache->{bug_validators} = $validators;
-    return $cache->{bug_validators};
+    return $validators;
 };
 
 use constant UPDATE_VALIDATORS => {
index 13e435e86ef233e77b6e5d72e417c9d1478cabfb..faef9f07d66e4ae07ea942d907c6692182badd2d 100644 (file)
@@ -675,6 +675,32 @@ L<Bugzilla::Object/update> returns.
 
 =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
 
 This is a simple way to add your own pages to Bugzilla. This hooks C<page.cgi>,
index 0bb865ea60b3627d69302f3f7628472ef454b837..75aa533ca09ce071ac3c8ed6f8b3a74aa837299e 100644 (file)
@@ -288,7 +288,7 @@ sub set {
                             { object => $self, field => $field,
                               value => $value });
 
-    my %validators = (%{$self->VALIDATORS}, %{$self->UPDATE_VALIDATORS});
+    my %validators = (%{$self->_get_validators}, %{$self->UPDATE_VALIDATORS});
     if (exists $validators{$field}) {
         my $validator = $validators{$field};
         $value = $self->$validator($value, $field);
@@ -430,7 +430,7 @@ sub check_required_create_fields {
 sub run_create_validators {
     my ($class, $params) = @_;
 
-    my $validators = $class->VALIDATORS;
+    my $validators = $class->_get_validators;
 
     my %field_values;
     # We do the sort just to make sure that validation always
@@ -487,6 +487,27 @@ sub get_all {
 
 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;
 
 __END__
index 1a483ad536e2b0d2e79db8aeb28114ff474aadfa..5f4cdf99522966ac9cf08481685d68e1e58a5a29 100644 (file)
@@ -25,6 +25,7 @@ use strict;
 use base qw(Bugzilla::Extension);
 
 use Bugzilla::Constants;
+use Bugzilla::Error;
 use Bugzilla::Group;
 use Bugzilla::User;
 use Bugzilla::Util qw(diff_arrays html_quote);
@@ -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 {
     my ($self, $args) = @_;
     
index df5a203dd3504339a15da8a5f160c8dbf2ababf0..50d20a9f2ac446727a726b630d62fb1008d74ac6 100644 (file)
@@ -9,4 +9,7 @@
 [% IF error == "example_my_error" %]
    [% title = "Example Error Title" %]
    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 %]