From f6fc02e572ba07782a272e8fc8f9f45e13ba4896 Mon Sep 17 00:00:00 2001 From: Max Kanat-Alexander Date: Wed, 10 Feb 2010 16:00:32 -0800 Subject: Bug 545524: New Hook: object_validators r=mkanat, a=mkanat (module owner) --- Bugzilla/Bug.pm | 5 +-- Bugzilla/Hook.pm | 26 ++++++++++++++ Bugzilla/Object.pm | 25 ++++++++++++-- extensions/Example/Extension.pm | 40 ++++++++++++++++++++++ .../hook/global/user-error-errors.html.tmpl | 3 ++ 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 37df30707..336b9cfe1 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -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 => { diff --git a/Bugzilla/Hook.pm b/Bugzilla/Hook.pm index 13e435e86..faef9f07d 100644 --- a/Bugzilla/Hook.pm +++ b/Bugzilla/Hook.pm @@ -675,6 +675,32 @@ L returns. =back +=head2 object_validators + +Allows you to add new items to L for +particular classes. + +Params: + +=over + +=item C + +The name of the class that C 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 + +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, diff --git a/Bugzilla/Object.pm b/Bugzilla/Object.pm index 0bb865ea6..75aa533ca 100644 --- a/Bugzilla/Object.pm +++ b/Bugzilla/Object.pm @@ -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__ diff --git a/extensions/Example/Extension.pm b/extensions/Example/Extension.pm index 1a483ad53..5f4cdf995 100644 --- a/extensions/Example/Extension.pm +++ b/extensions/Example/Extension.pm @@ -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) = @_; diff --git a/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl index df5a203dd..50d20a9f2 100644 --- a/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl +++ b/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl @@ -9,4 +9,7 @@ [% IF error == "example_my_error" %] [% title = "Example Error Title" %] This is the error message! It contains some html. +[% ELSIF error == "example_short_desc_invalid" %] + [% title = "Bad Summary" %] + The Summary must contain the word "example". [% END %] -- cgit v1.2.3-24-g4f1b