]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 525606: Make the template_before_process hook run whenever a template is loaded...
authormkanat%bugzilla.org <>
Thu, 17 Dec 2009 05:27:10 +0000 (05:27 +0000)
committermkanat%bugzilla.org <>
Thu, 17 Dec 2009 05:27:10 +0000 (05:27 +0000)
Patch by Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat

Bugzilla/Hook.pm
Bugzilla/Template.pm
Bugzilla/Template/Context.pm [new file with mode: 0644]
Bugzilla/Template/Plugin/Hook.pm
extensions/Example/Extension.pm

index 5093db903f698fc33b0e309dbe7e7474ba551947..44b5c3c5841a625037d0204533689ecbb62da6e7 100644 (file)
@@ -734,15 +734,25 @@ look at the code for C<create> in L<Bugzilla::Template>.)
 
 =head2 template_before_process
 
+This hook is called any time Bugzilla processes a template file, including
+calls to C<< $template->process >>, C<PROCESS> statements in templates,
+and C<INCLUDE> statements in templates. It is not called when templates
+process a C<BLOCK>, only when they process a file.
+
 This hook allows you to define additional variables that will be available to
-the template being processed. You probably want to restrict your hook
-to operating only if a certain file is being loaded (which is why you
-get a C<file> argument below). Otherwise, modifying the C<vars> argument
-will affect every single template in Bugzilla.
+the template being processed, or to modify the variables that are currently
+in the template. It works exactly as though you inserted code to modify
+template variables at the top of a template.
+
+You probably want to restrict this hook to operating only if a certain 
+file is being processed (which is why you get a C<file> argument
+below). Otherwise, modifying the C<vars> argument will affect every single
+template in Bugzilla.
 
-Note that this is only called on the top-level C<< $template->process >>
-call. It is not called for C<[% PROCESS %]> or C<[% INCLUDE %]> statements 
-in templates.
+B<Note:> This hook is not called if you are already in this hook.
+(That is, it won't call itself recursively.) This prevents infinite
+recursion in situations where this hook needs to process a template
+(such as if this hook throws an error).
 
 Params:
 
@@ -750,28 +760,25 @@ Params:
 
 =item C<vars>
 
-The template vars hashref--these are the values that get passed to the
-template. Adding new keys to this hashref will cause those new values
-to also get passed to the template.
+This is the entire set of variables that the current template can see.
+Technically, this is a L<Template::Stash> object, but you can just
+use it like a hashref if you want.
 
-=item C<file> 
+=item C<file>
 
-The name of the template being processed. This is relative
-to the main template directory for the language (i.e. for
+The name of the template file being processed. This is relative to the
+main template directory for the language (i.e. for
 F<template/en/default/bug/show.html.tmpl>, this variable will contain
 C<bug/show.html.tmpl>).
 
-=item C<template>
+=item C<context>
 
-The L<Bugzilla::Template> object that C<process> was called on.
+A L<Template::Context> object. Usually you will not have to use this, but
+if you need information about the template itself (other than just its
+name), you can get it from here.
 
 =back
 
-B<Note:> This hook is not called if you are already in this hook.
-(That is, it won't call itself recursively.) This prevents infinite
-recursion in situations where this hook needs to process a template
-(such as if this hook throws an error).
-
 =head2 webservice
 
 This hook allows you to add your own modules to the WebService. (See
index c8e3bc69c42165e050600ffa9d005b99dffbf3dc..0463830948285f7ab5b718d129f972e8f654fa9e 100644 (file)
@@ -80,25 +80,6 @@ sub _load_constants {
     return \%constants;
 }
 
-# Overload Template::Process in order to add a hook to allow additional
-# variables to be made available by an extension
-sub process {
-    my $self = shift;
-    my ($file, $vars) = @_;
-
-    # This hook can't call itself recursively, because otherwise we
-    # end up with problems when we throw an error inside of extensions
-    # (they end up in infinite recursion, because throwing an error involves
-    # processing a template).
-    if (!Bugzilla::Hook::in('template_before_process')) {
-        Bugzilla::Hook::process('template_before_process', 
-                                { vars => $vars, file => $file, 
-                                  template => $self });
-    }
-
-    return $self->SUPER::process(@_);
-}
-
 # Returns the path to the templates based on the Accept-Language
 # settings of the user and of the available languages
 # If no Accept-Language is present it uses the defined default
@@ -487,7 +468,7 @@ sub create {
         COMPILE_DIR => bz_locations()->{'datadir'} . "/template",
 
         # Initialize templates (f.e. by loading plugins like Hook).
-        PRE_PROCESS => "global/initialize.none.tmpl",
+        PRE_PROCESS => ["global/initialize.none.tmpl"],
 
         ENCODING => Bugzilla->params->{'utf8'} ? 'UTF-8' : undef,
 
@@ -802,6 +783,8 @@ sub create {
         },
     };
 
+    local $Template::Config::CONTEXT = 'Bugzilla::Template::Context';
+
     Bugzilla::Hook::process('template_before_create', { config => $config });
     my $template = $class->new($config) 
         || die("Template creation failed: " . $class->error());
diff --git a/Bugzilla/Template/Context.pm b/Bugzilla/Template/Context.pm
new file mode 100644 (file)
index 0000000..7923603
--- /dev/null
@@ -0,0 +1,104 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is ITA Software.
+# Portions created by the Initial Developer are Copyright (C) 2009 
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander <mkanat@bugzilla.org>
+
+# This exists to implement the template-before_process hook.
+package Bugzilla::Template::Context;
+use strict;
+use base qw(Template::Context);
+
+use Bugzilla::Hook;
+use Scalar::Util qw(blessed);
+
+sub process {
+    my $self = shift;
+    # We don't want to run the template_before_process hook for
+    # template hooks (but we do want it to run if a hook calls
+    # PROCESS inside itself). The problem is that the {component}->{name} of
+    # hooks is unreliable--sometimes it starts with ./ and it's the
+    # full path to the hook template, and sometimes it's just the relative
+    # name (like hook/global/field-descs-end.none.tmpl). Also, calling
+    # template_before_process for hook templates doesn't seem too useful,
+    # because that's already part of the extension and they should be able
+    # to modify their hook if they want (or just modify the variables in the
+    # calling template).
+    if (not delete $self->{bz_in_hook}) {
+        $self->{bz_in_process} = 1;
+    }
+    my $result = $self->SUPER::process(@_);
+    delete $self->{bz_in_process};
+    return $result;
+}
+
+# This method is called by Template-Toolkit exactly once per template or
+# block (look at a compiled template) so this is an ideal place for us to
+# modify the variables before a template or block runs.
+#
+# We don't do it during Context::process because at that time
+# our stash hasn't been set correctly--the parameters we were passed
+# in the PROCESS or INCLUDE directive haven't been set, and if we're
+# in an INCLUDE, the stash is not yet localized during process().
+sub stash {
+    my $self = shift;
+    my $stash = $self->SUPER::stash(@_);
+
+    my $name = $stash->{component}->{name};
+    my $pre_process = $self->config->{PRE_PROCESS};
+
+    # Checking bz_in_process tells us that we were indeed called as part of a
+    # Context::process, and not at some other point. 
+    #
+    # Checking $name makes sure that we're processing a file, and not just a
+    # block, by checking that the name has a period in it. We don't allow
+    # blocks because their names are too unreliable--an extension could have
+    # a block with the same name, or multiple files could have a same-named
+    # block, and then your extension would malfunction.
+    #
+    # We also make sure that we don't run, ever, during the PRE_PROCESS
+    # templates, because if somebody calls Throw*Error globally inside of
+    # template_before_process, that causes an infinite recursion into
+    # the PRE_PROCESS templates (because Bugzilla, while inside 
+    # global/intialize.none.tmpl, loads the template again to create the
+    # template object for Throw*Error).
+    #
+    # Checking Bugzilla::Hook::in prevents infinite recursion on this hook.
+    if ($self->{bz_in_process} and $name =~ /\./
+        and !grep($_ eq $name, @$pre_process)
+        and !Bugzilla::Hook::in('template_before_process'))
+    {
+        Bugzilla::Hook::process("template_before_process",
+                                { vars => $stash, context => $self,
+                                  file => $name });
+    }
+
+    # This prevents other calls to stash() that might somehow happen
+    # later in the file from also triggering the hook.
+    delete $self->{bz_in_process};
+
+    return $stash;
+}
+
+# We need a DESTROY sub for the same reason that Bugzilla::CGI does.
+sub DESTROY {
+    my $self = shift;
+    $self->SUPER::DESTROY(@_);
+};
+
+1;
index 9c292d7260df08366692f2f8c6e45d5d0db7b4ba..e993060dd554de88e4a471ab12f597489ee065d1 100644 (file)
@@ -68,6 +68,7 @@ sub process {
 
     # process() accepts an arrayref of templates, so we just pass the whole
     # arrayref.
+    $context->{bz_in_hook} = 1; # See Bugzilla::Template::Context
     return $context->process($cache->{"${lang}__$extension_template"});
 }
 
index 615f7740bf1423ae7f87c8c06541a3ec4512b6d1..c0e44aa5986466e186d03c1bb8d46add9060ffda 100644 (file)
@@ -448,12 +448,10 @@ sub template_before_create {
 sub template_before_process {
     my ($self, $args) = @_;
     
-    my ($vars, $file, $template) = @$args{qw(vars file template)};
-    
-    $vars->{'example'} = 1;
-    
-    if ($file =~ m{^bug/show}) {
-        $vars->{'showing_a_bug'} = 1;
+    my ($vars, $file, $context) = @$args{qw(vars file context)};
+
+    if ($file eq 'bug/edit.html.tmpl') {
+        $vars->{'viewing_the_bug_form'} = 1;
     }
 }