Commit b7c87a72 authored by mkanat%bugzilla.org's avatar mkanat%bugzilla.org

Bug 339380: Make Bugzilla::Component use Bugzilla::Object

Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=myk
parent 6255b084
...@@ -21,6 +21,8 @@ use strict; ...@@ -21,6 +21,8 @@ use strict;
package Bugzilla::Component; package Bugzilla::Component;
use base qw(Bugzilla::Object);
use Bugzilla::Util; use Bugzilla::Util;
use Bugzilla::Error; use Bugzilla::Error;
use Bugzilla::User; use Bugzilla::User;
...@@ -30,68 +32,50 @@ use Bugzilla::FlagType; ...@@ -30,68 +32,50 @@ use Bugzilla::FlagType;
#### Initialization #### #### Initialization ####
############################### ###############################
use constant DB_TABLE => 'components';
use constant DB_COLUMNS => qw( use constant DB_COLUMNS => qw(
components.id id
components.name name
components.product_id product_id
components.initialowner initialowner
components.initialqacontact initialqacontact
components.description description
); );
our $columns = join(", ", DB_COLUMNS);
############################### ###############################
#### Methods #### #### Methods ####
############################### ###############################
sub new { sub new {
my $invocant = shift; my $class = shift;
my $class = ref($invocant) || $invocant; my $param = shift;
my $self = {};
bless($self, $class);
return $self->_init(@_);
}
sub _init {
my $self = shift;
my ($param) = (@_);
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
my $id = $param unless (ref $param eq 'HASH'); my $product;
my $component; if (ref $param) {
$product = $param->{product};
if (defined $id) { my $name = $param->{name};
detaint_natural($id) if (!defined $product) {
|| ThrowCodeError('param_must_be_numeric', ThrowCodeError('bad_arg',
{function => 'Bugzilla::Component::_init'}); {argument => 'product',
function => "${class}::new"});
$component = $dbh->selectrow_hashref(qq{ }
SELECT $columns FROM components if (!defined $name) {
WHERE id = ?}, undef, $id); ThrowCodeError('bad_arg',
{argument => 'name',
} elsif (defined $param->{'product_id'} function => "${class}::new"});
&& detaint_natural($param->{'product_id'}) }
&& defined $param->{'name'}) {
my $condition = 'product_id = ? AND name = ?';
trick_taint($param->{'name'}); my @values = ($product->id, $name);
$param = { condition => $condition, values => \@values };
$component = $dbh->selectrow_hashref(qq{
SELECT $columns FROM components
WHERE name = ? AND product_id = ?}, undef,
($param->{'name'}, $param->{'product_id'}));
} else {
ThrowCodeError('bad_arg',
{argument => 'param',
function => 'Bugzilla::Component::_init'});
} }
return undef unless (defined $component); unshift @_, $param;
my $component = $class->SUPER::new(@_);
foreach my $field (keys %$component) { $component->{product} = $product if $product;
$self->{$field} = $component->{$field}; return $component;
}
return $self;
} }
sub bug_count { sub bug_count {
...@@ -204,8 +188,8 @@ sub check_component { ...@@ -204,8 +188,8 @@ sub check_component {
} }
my $component = my $component =
new Bugzilla::Component({product_id => $product->id, new Bugzilla::Component({product => $product,
name => $comp_name}); name => $comp_name});
unless ($component) { unless ($component) {
ThrowUserError('component_not_valid', ThrowUserError('component_not_valid',
{'product' => $product->name, {'product' => $product->name,
...@@ -227,8 +211,8 @@ Bugzilla::Component - Bugzilla product component class. ...@@ -227,8 +211,8 @@ Bugzilla::Component - Bugzilla product component class.
use Bugzilla::Component; use Bugzilla::Component;
my $component = new Bugzilla::Component(1); my $component = new Bugzilla::Component(1);
my $component = new Bugzilla::Component({product_id => 1, my $component = new Bugzilla::Component({product => $product,
name => 'AcmeComp'}); name => 'AcmeComp'});
my $bug_count = $component->bug_count(); my $bug_count = $component->bug_count();
my $bug_ids = $component->bug_ids(); my $bug_ids = $component->bug_ids();
......
...@@ -60,6 +60,8 @@ sub _init { ...@@ -60,6 +60,8 @@ sub _init {
my $object; my $object;
if (defined $id) { if (defined $id) {
# We special-case if somebody specifies an ID, so that we can
# validate it as numeric.
detaint_natural($id) detaint_natural($id)
|| ThrowCodeError('param_must_be_numeric', || ThrowCodeError('param_must_be_numeric',
{function => $class . '::_init'}); {function => $class . '::_init'});
...@@ -67,23 +69,40 @@ sub _init { ...@@ -67,23 +69,40 @@ sub _init {
$object = $dbh->selectrow_hashref(qq{ $object = $dbh->selectrow_hashref(qq{
SELECT $columns FROM $table SELECT $columns FROM $table
WHERE $id_field = ?}, undef, $id); WHERE $id_field = ?}, undef, $id);
} elsif (defined $param->{'name'}) {
trick_taint($param->{'name'});
$object = $dbh->selectrow_hashref(qq{
SELECT $columns FROM $table
WHERE } . $dbh->sql_istrcmp($name_field, '?'),
undef, $param->{'name'});
} else { } else {
ThrowCodeError('bad_arg', unless (defined $param->{name} || (defined $param->{'condition'}
{argument => 'param', && defined $param->{'values'}))
function => $class . '::_init'}); {
ThrowCodeError('bad_arg', { argument => 'param',
function => $class . '::new' });
}
my ($condition, @values);
if (defined $param->{name}) {
$condition = $dbh->sql_istrcmp($name_field, '?');
push(@values, $param->{name});
}
elsif (defined $param->{'condition'} && defined $param->{'values'}) {
caller->isa('Bugzilla::Object')
|| ThrowCodeError('protection_violation',
{ caller => caller,
function => $class . '::new',
argument => 'condition/values' });
$condition = $param->{'condition'};
push(@values, @{$param->{'values'}});
}
map { trick_taint($_) } @values;
$object = $dbh->selectrow_hashref(
"SELECT $columns FROM $table WHERE $condition", undef, @values);
} }
return $object; return $object;
} }
sub new_from_list { sub new_from_list {
my $class = shift; my $invocant = shift;
my $class = ref($invocant) || $invocant;
my ($id_list) = @_; my ($id_list) = @_;
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
my $columns = join(',', $class->DB_COLUMNS); my $columns = join(',', $class->DB_COLUMNS);
...@@ -363,17 +382,47 @@ the L</ID_FIELD> usually can't be updated.) ...@@ -363,17 +382,47 @@ the L</ID_FIELD> usually can't be updated.)
=item C<new($param)> =item C<new($param)>
Description: The constructor is used to load an existing object =over
from the database, by id or by name.
=item B<Description>
The constructor is used to load an existing object from the database,
by id or by name.
Params: $param - If you pass an integer, the integer is the =item B<Params>
id of the object, from the database, that we
want to read in. If you pass in a hash with If you pass an integer, the integer is the id of the object,
C<name> key, then the value of the name key from the database, that we want to read in. (id is defined
is the case-insensitive name of the object from as the value in the L</ID_FIELD> column).
the DB.
If you pass in a hash, you can pass a C<name> key. The
value of the C<name> key is the case-insensitive name of the object
(from L</NAME_FIELD>) in the DB.
B<Additional Parameters Available for Subclasses>
If you are a subclass of C<Bugzilla::Object>, you can pass
C<condition> and C<values> as hash keys, instead of the above.
C<condition> is a set of SQL conditions for the WHERE clause, which contain
placeholders.
C<values> is a reference to an array. The array contains the values
for each placeholder in C<condition>, in order.
Returns: A fully-initialized object. This is to allow subclasses to have complex parameters, and then to
translate those parameters into C<condition> and C<values> when they
call C<$self->SUPER::new> (which is this function, usually).
If you try to call C<new> outside of a subclass with the C<condition>
and C<values> parameters, Bugzilla will throw an error. These parameters
are intended B<only> for use by subclasses.
=item B<Returns>
A fully-initialized object.
=back
=item C<new_from_list(\@id_list)> =item C<new_from_list(\@id_list)>
......
...@@ -65,12 +65,8 @@ sub components { ...@@ -65,12 +65,8 @@ sub components {
WHERE product_id = ? WHERE product_id = ?
ORDER BY name}, undef, $self->id); ORDER BY name}, undef, $self->id);
my @components;
require Bugzilla::Component; require Bugzilla::Component;
foreach my $id (@$ids) { $self->{components} = Bugzilla::Component->new_from_list($ids);
push @components, new Bugzilla::Component($id);
}
$self->{components} = \@components;
} }
return $self->{components}; return $self->{components};
} }
......
...@@ -931,10 +931,7 @@ sub product_responsibilities { ...@@ -931,10 +931,7 @@ sub product_responsibilities {
# We cannot |use| it, because Component.pm already |use|s User.pm. # We cannot |use| it, because Component.pm already |use|s User.pm.
require Bugzilla::Component; require Bugzilla::Component;
my @components; $self->{'product_resp'} = Bugzilla::Component->new_from_list($comp_ids);
push(@components, new Bugzilla::Component($_)) foreach (@$comp_ids);
$self->{'product_resp'} = \@components;
return $self->{'product_resp'}; return $self->{'product_resp'};
} }
......
...@@ -168,7 +168,7 @@ if ($action eq 'new') { ...@@ -168,7 +168,7 @@ if ($action eq 'new') {
} }
my $component = my $component =
new Bugzilla::Component({product_id => $product->id, new Bugzilla::Component({product => $product,
name => $comp_name}); name => $comp_name});
if ($component) { if ($component) {
...@@ -200,7 +200,7 @@ if ($action eq 'new') { ...@@ -200,7 +200,7 @@ if ($action eq 'new') {
($product->id, $comp_name, $description, ($product->id, $comp_name, $description,
$default_assignee_id, $default_qa_contact_id)); $default_assignee_id, $default_qa_contact_id));
$component = new Bugzilla::Component({ product_id => $product->id, $component = new Bugzilla::Component({ product => $product,
name => $comp_name }); name => $comp_name });
my $sth = $dbh->prepare("INSERT INTO component_cc my $sth = $dbh->prepare("INSERT INTO component_cc
...@@ -383,7 +383,7 @@ if ($action eq 'update') { ...@@ -383,7 +383,7 @@ if ($action eq 'update') {
if ($comp_name ne $component_old->name) { if ($comp_name ne $component_old->name) {
my $component = my $component =
new Bugzilla::Component({product_id => $product->id, new Bugzilla::Component({product => $product,
name => $comp_name}); name => $comp_name});
if ($component) { if ($component) {
ThrowUserError('component_already_exists', ThrowUserError('component_already_exists',
......
...@@ -326,8 +326,8 @@ sub init() { ...@@ -326,8 +326,8 @@ sub init() {
moved-default-product. \n", "REOPEN", $exporter); moved-default-product. \n", "REOPEN", $exporter);
my $def_component = new Bugzilla::Component( my $def_component = new Bugzilla::Component(
{ {
product_id => $def_product->id, product => $def_product,
name => $params->{"moved-default-component"} name => $params->{"moved-default-component"}
}) })
|| Error("Cannot import these bugs because an invalid default || Error("Cannot import these bugs because an invalid default
component was defined for the target db." component was defined for the target db."
...@@ -622,8 +622,8 @@ sub process_bug { ...@@ -622,8 +622,8 @@ sub process_bug {
new Bugzilla::Product( { name => $params->{"moved-default-product"} } ); new Bugzilla::Product( { name => $params->{"moved-default-product"} } );
my $def_component = new Bugzilla::Component( my $def_component = new Bugzilla::Component(
{ {
product_id => $def_product->id, product => $def_product,
name => $params->{"moved-default-component"} name => $params->{"moved-default-component"}
} }
); );
my $product; my $product;
...@@ -643,8 +643,8 @@ sub process_bug { ...@@ -643,8 +643,8 @@ sub process_bug {
if ( defined $bug_fields{'component'} ) { if ( defined $bug_fields{'component'} ) {
$component = new Bugzilla::Component( $component = new Bugzilla::Component(
{ {
product_id => $product->id, product => $product,
name => $bug_fields{'component'} name => $bug_fields{'component'}
} }
); );
unless ($component) { unless ($component) {
......
...@@ -325,6 +325,11 @@ ...@@ -325,6 +325,11 @@
[% ELSIF error == "protection_violation" %] [% ELSIF error == "protection_violation" %]
The function <code>[% function FILTER html %]</code> was called The function <code>[% function FILTER html %]</code> was called
[% IF argument %]
with the argument <code>[% argument FILTER html %]</code>
[% END %]
from from
[% IF caller %] [% IF caller %]
......
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