sub template {
request_cache->{template}
- //= Bugzilla::Template->create(preload => $preload_templates);
+ ||= Bugzilla::Template->create(preload => $preload_templates);
request_cache->{template}->{_is_main} = 1;
return request_cache->{template};
}
sub extensions {
- my $cache = request_cache;
- if (!$cache->{extensions}) {
- my $extension_packages = Bugzilla::Extension->load_all();
- my @extensions;
- foreach my $package (@$extension_packages) {
- my $extension = $package->new();
- if ($extension->enabled) {
- push(@extensions, $extension);
- }
+ state $extensions;
+ return $extensions if $extensions;
+ my $extension_packages = Bugzilla::Extension->load_all();
+ $extensions = [];
+ foreach my $package (@$extension_packages) {
+ if ($package->enabled) {
+ push @$extensions, $package;
}
- $cache->{extensions} = \@extensions;
}
- return $cache->{extensions};
+ return $extensions;
}
sub cgi {
use File::Basename;
use File::Spec;
+use List::Util qw(any);
+use Scalar::Util qw(refaddr);
BEGIN { push @INC, \&INC_HOOK }
return;
}
-####################
-# Subclass Methods #
-####################
-
-sub new {
- my ($class, $params) = @_;
- $params ||= {};
- bless $params, $class;
- return $params;
-}
-
#######################################
# Class (Bugzilla::Extension) Methods #
#######################################
push(@$EXTENSIONS, $package);
}
+ Bugzilla::Hook::finalize($EXTENSIONS);
+
return $EXTENSIONS;
}
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::Hook;
-
-use 5.10.1;
-use strict;
-use warnings;
+use Mojo::Base -strict;
+
+use Bugzilla::Logging;
+use List::Util qw(any);
+use Package::Stash;
+use Sub::Identify qw(stash_name);
+use Type::Params qw(compile);
+use Type::Utils -all;
+use Types::Standard -all;
+
+my %HOOKS;
+
+sub finalize {
+ state $check = compile(ArrayRef[ClassName]);
+ my ($extensions) = $check->(@_);
+
+ foreach my $extension (@$extensions) {
+ my $stash = Package::Stash->new($extension);
+ foreach my $name ($stash->list_all_symbols('CODE')) {
+ next if $name =~ /^[A-Z_]+/;
+ my $hook = $extension->can($name) or die "$extension has no method '$name'";
+ next if stash_name($hook) ne $extension; # skip imported methods.
+ push @{$HOOKS{$name}}, [$hook, $extension];
+ }
+ }
+}
sub process {
my ($name, $args) = @_;
- _entering($name);
-
- foreach my $extension (@{Bugzilla->extensions}) {
- if ($extension->can($name)) {
- $extension->$name($args);
+ # this state variable is used to execute the load_all() method only once.
+ # The double-negation is used because I don't want to hold a reference to it.
+ state $once = !!Bugzilla::Extension->load_all();
+ if ($HOOKS{$name}) {
+ foreach my $hook (@{$HOOKS{$name}}) {
+ $hook->[0]->($hook->[1], $args);
}
}
-
- _leaving($name);
-}
-
-sub in {
- my $hook_name = shift;
- my $currently_in = Bugzilla->request_cache->{hook_stack}->[-1] || '';
- return $hook_name eq $currently_in ? 1 : 0;
-}
-
-sub _entering {
- my ($hook_name) = @_;
- my $hook_stack = Bugzilla->request_cache->{hook_stack} ||= [];
- push(@$hook_stack, $hook_name);
-}
-
-sub _leaving {
- pop @{Bugzilla->request_cache->{hook_stack}};
+ return;
}
1;
# 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().
+our $in_template_before_process = 0;
sub stash {
my $self = shift;
my $stash = $self->SUPER::stash(@_);
if ( $self->{bz_in_process}
and $name =~ /\./
and !grep($_ eq $name, @$pre_process)
- and !Bugzilla::Hook::in('template_before_process'))
+ and !$in_template_before_process)
{
+ local $in_template_before_process = 1;
Bugzilla::Hook::process("template_before_process",
{vars => $stash, context => $self, file => $name});
}
sub _enabled {
my ($self) = @_;
- if (!exists $self->{'enabled'}) {
+ my $cache = Bugzilla->request_cache->{+__PACKAGE__} //= {};
+
+ if (!exists $cache->{'enabled'}) {
my $push = Bugzilla->push_ext;
- $self->{'enabled'} = $push->config->{enabled} eq 'Enabled';
- if ($self->{'enabled'}) {
+ $cache->{'enabled'} = $push->config->{enabled} eq 'Enabled';
+ if ($cache->{'enabled'}) {
# if no connectors are enabled, no need to push anything
- $self->{'enabled'} = 0;
+ $cache->{'enabled'} = 0;
foreach my $connector (Bugzilla->push_ext->connectors->list) {
if ($connector->enabled) {
- $self->{'enabled'} = 1;
+ $cache->{'enabled'} = 1;
last;
}
}
}
}
- return $self->{'enabled'};
+ return $cache->{'enabled'};
}
#
sub _can_restrict_comments {
my ($self, $object) = @_;
return unless $object->isa('Bugzilla::Bug');
- $self->{setter_group} ||= Bugzilla->params->{'restrict_comments_enable_group'};
- return Bugzilla->user->in_group($self->{setter_group});
+ return Bugzilla->user->in_group(
+ Bugzilla->params->{'restrict_comments_enable_group'});
}
sub object_end_of_set_all {