WIP BUG_ID reverse relationships (implementation different to upstream)

hinted-selects
Vitaliy Filippov 2014-06-11 19:28:29 +04:00
parent 68ff25fef5
commit d5e13b4a67
8 changed files with 139 additions and 27 deletions

View File

@ -3973,7 +3973,7 @@ sub get_ids
{
return $self->{$fn};
}
elsif ($field && $field->type == FIELD_TYPE_MULTI_SELECT)
elsif ($field && ($field->type == FIELD_TYPE_MULTI_SELECT || $field->type == FIELD_TYPE_BUG_ID_REV))
{
return $self->$fn;
}
@ -4000,6 +4000,10 @@ sub get_object
{
$self->{$attr} = $field->value_type->new_from_list($self->$fn);
}
elsif ($field && $field->type == FIELD_TYPE_BUG_ID_REV)
{
$self->{$attr} = Bugzilla::Bug->new_from_list($self->$fn);
}
else
{
die "Invalid join requested - ".__PACKAGE__."::$attr";
@ -4015,15 +4019,19 @@ sub get_string
my $f = ref $field ? $field->name : $field;
$field = Bugzilla->get_field($field) if !ref $field;
my $value;
if ($field->type == FIELD_TYPE_SINGLE_SELECT)
if ($field && $field->type == FIELD_TYPE_SINGLE_SELECT)
{
$value = $self->get_object($f) && $self->get_object($f)->name;
}
elsif ($field->type == FIELD_TYPE_MULTI_SELECT)
elsif ($field && $field->type == FIELD_TYPE_MULTI_SELECT)
{
$value = join ', ', map { $_->name } @{$self->get_object($f)};
}
elsif ($field->type != FIELD_TYPE_UNKNOWN || SCALAR_FORMAT->{$f})
elsif ($field && $field->type == FIELD_TYPE_BUG_ID_REV)
{
$value = join ', ', @{ $self->$f };
}
elsif ($field && $field->type != FIELD_TYPE_UNKNOWN || SCALAR_FORMAT->{$f})
{
$value = $self->$f;
}
@ -4123,12 +4131,22 @@ sub AUTOLOAD
}
my $field = Bugzilla->get_field($attr);
if ($field && $field->type == FIELD_TYPE_MULTI_SELECT)
if ($field)
{
$self->{$attr} ||= Bugzilla->dbh->selectcol_arrayref(
"SELECT id FROM bug_$attr, $attr WHERE value_id=id AND bug_id=? ORDER BY value",
undef, $self->id);
return $self->{$attr};
if ($field->type == FIELD_TYPE_MULTI_SELECT)
{
$self->{$attr} ||= Bugzilla->dbh->selectcol_arrayref(
"SELECT id FROM bug_$attr, $attr WHERE value_id=id AND bug_id=? ORDER BY value",
undef, $self->id);
return $self->{$attr};
}
elsif ($field->type == FIELD_TYPE_BUG_ID_REV)
{
$self->{$attr} ||= Bugzilla->dbh->selectcol_arrayref(
"SELECT bug_id FROM bugs WHERE ".$field->value_field->name." = ".$self->id
);
return $self->{$attr};
}
}
return '';

View File

@ -130,6 +130,7 @@ use Cwd qw(abs_path);
FIELD_TYPE_KEYWORDS
FIELD_TYPE_NUMERIC
FIELD_TYPE_EXTURL
FIELD_TYPE_BUG_ID_REV
TIMETRACKING_FIELDS
@ -382,6 +383,7 @@ use constant FIELD_TYPE_KEYWORDS => 8;
use constant FIELD_TYPE_NUMERIC => 30;
use constant FIELD_TYPE_EXTURL => 31;
use constant FIELD_TYPE_BUG_ID_REV => 32;
use constant BUG_ID_ADD_TO_BLOCKED => 1;
use constant BUG_ID_ADD_TO_DEPENDSON => 2;

View File

@ -130,7 +130,7 @@ use constant VALIDATORS => {
};
use constant UPDATE_VALIDATORS => {
value_field_id => \&_check_value_field_id,
value_field_id => \&_check_value_field_id,
};
use constant UPDATE_COLUMNS => qw(
@ -306,7 +306,7 @@ sub _check_type
# higher field type is added.
if (!detaint_natural($type) || $type < FIELD_TYPE_UNKNOWN ||
$type > FIELD_TYPE_KEYWORDS && $type < FIELD_TYPE_NUMERIC ||
$type > FIELD_TYPE_EXTURL)
$type > FIELD_TYPE_BUG_ID_REV)
{
ThrowCodeError('invalid_customfield_type', { type => $saved_type });
}
@ -315,9 +315,27 @@ sub _check_type
sub _check_value_field_id
{
my ($invocant, $field_id, $is_select) = @_;
$is_select = $invocant->is_select if !defined $is_select;
if ($field_id && !$is_select)
my ($invocant, $field_id, undef, $type) = @_;
$type = $invocant->type if !defined $type;
if ($type == FIELD_TYPE_BUG_ID_REV)
{
# For fields of type "reverse relation of BUG_ID field"
# value_field indicates the needed direct relation
my $field = Bugzilla->get_field(trim($field_id));
if (!$field || $field->type != FIELD_TYPE_BUG_ID)
{
ThrowUserError('direct_field_needed_for_reverse');
}
for (Bugzilla->get_fields({ type => FIELD_TYPE_BUG_ID_REV, value_field_id => $field->id }))
{
if (!ref $invocant || $_->id != $invocant->id)
{
ThrowUserError('duplicate_reverse_field');
}
}
return $field->id;
}
if ($field_id && $type != FIELD_TYPE_SINGLE_SELECT && $type != FIELD_TYPE_MULTI_SELECT)
{
ThrowUserError('field_value_control_select_only');
}
@ -729,7 +747,7 @@ sub value_field
sub value_field_id
{
my $self = shift;
return undef if !$self->is_select;
return undef if !$self->is_select && $self->type != FIELD_TYPE_BUG_ID_REV;
return $self->{value_field_id};
}
@ -930,7 +948,7 @@ sub update
# FIXME Merge something like VALIDATOR_DEPENDENCIES from 4.4
if ($self->{type} != FIELD_TYPE_BUG_ID)
{
$self->{add_to_deps} = undef;
$self->{add_to_deps} = 0;
}
if ($self->{type} != FIELD_TYPE_EXTURL)
{
@ -1054,15 +1072,12 @@ sub run_create_validators
ThrowCodeError('field_type_not_specified');
}
$params->{value_field_id} = $class->_check_value_field_id(
$params->{value_field_id},
($type == FIELD_TYPE_SINGLE_SELECT || $type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0
);
$params->{value_field_id} = $class->_check_value_field_id($params->{value_field_id}, undef, $type);
# FIXME Merge something like VALIDATOR_DEPENDENCIES from 4.4
if ($type != FIELD_TYPE_BUG_ID)
{
$params->{add_to_deps} = undef;
$params->{add_to_deps} = 0;
}
if ($type != FIELD_TYPE_EXTURL)
{

View File

@ -130,6 +130,7 @@ sub update_fielddefs_definition {
$dbh->do('UPDATE fielddefs SET type='.FIELD_TYPE_EXTURL.' WHERE custom=1 AND type=9');
}
# This column is used for fast lookup of fields used in bug history
if (!$dbh->bz_column_info('fielddefs', 'has_activity'))
{
$dbh->bz_add_column('fielddefs', has_activity => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0});
@ -140,6 +141,26 @@ sub update_fielddefs_definition {
);
}
# Migrate reverse_desc (upstream implementation) into separate field objects
if ($dbh->bz_column_info('fielddefs', 'reverse_desc'))
{
my $rows = $dbh->selectall_arrayref(
'SELECT * FROM fielddefs WHERE custom=1 AND type='.FIELD_TYPE_BUG_ID.
' AND reverse_desc IS NOT NULL AND reverse_desc != \'\'', {Slice=>{}}
);
for (@$rows)
{
Bugzilla::Field->create({
name => $_->{name}.'_rev',
custom => 1,
description => $_->{reverse_desc},
type => FIELD_TYPE_BUG_ID_REV,
value_field_id => $_->{id},
});
}
$dbh->bz_drop_column('fielddefs', 'reverse_desc');
}
# Remember, this is not the function for adding general table changes.
# That is below. Add new changes to the fielddefs table above this
# comment.

View File

@ -67,13 +67,14 @@ $Bugzilla::messages->{en} = {
field_types => {
FIELD_TYPE_UNKNOWN() => 'Unknown Type',
FIELD_TYPE_FREETEXT() => 'Free Text',
FIELD_TYPE_EXTURL() => 'External URL',
FIELD_TYPE_SINGLE_SELECT() => 'Drop Down',
FIELD_TYPE_MULTI_SELECT() => 'Multiple-Selection Box',
FIELD_TYPE_TEXTAREA() => 'Large Text Box',
FIELD_TYPE_DATETIME() => 'Date/Time',
FIELD_TYPE_BUG_ID() => $terms->{Bug}.' ID',
FIELD_TYPE_NUMERIC() => 'Numeric',
FIELD_TYPE_EXTURL() => 'External URL',
FIELD_TYPE_BUG_ID_REV() => $terms->{Bug}.' ID reverse',
},
control_options => {
CONTROLMAPNA() => 'NA',

View File

@ -6,11 +6,30 @@ function onChangeType()
{
var type_field = document.getElementById('type');
var value_field = document.getElementById('value_field_id');
if (type_field.value == constants.FIELD_TYPE_SINGLE_SELECT
|| type_field.value == constants.FIELD_TYPE_MULTI_SELECT)
if (type_field.value == constants.FIELD_TYPE_SINGLE_SELECT ||
type_field.value == constants.FIELD_TYPE_MULTI_SELECT)
{
value_field.disabled = false;
document.getElementById('value_field_row').style.display = '';
}
else
{
value_field.disabled = true;
document.getElementById('value_field_row').style.display = 'none';
}
var rev_value_field = document.getElementById('bug_id_rev_value_field_id');
if (type_field.value == constants.FIELD_TYPE_BUG_ID_REV)
{
rev_value_field.name = 'value_field_id';
value_field.name = '';
document.getElementById('bug_id_rev_row').style.display = '';
}
else
{
rev_value_field.name = '';
value_field.name = 'value_field_id';
document.getElementById('bug_id_rev_row').style.display = 'none';
}
document.getElementById('add_to_deps').style.display
= document.getElementById('add_to_deps_title').style.display
= type_field.value == constants.FIELD_TYPE_BUG_ID ? '' : 'none';

View File

@ -30,7 +30,8 @@ var constants = {
FIELD_TYPE_SINGLE_SELECT: [% constants.FIELD_TYPE_SINGLE_SELECT %],
FIELD_TYPE_MULTI_SELECT: [% constants.FIELD_TYPE_MULTI_SELECT %],
FIELD_TYPE_BUG_ID: [% constants.FIELD_TYPE_BUG_ID %],
FIELD_TYPE_EXTURL: [% constants.FIELD_TYPE_EXTURL %]
FIELD_TYPE_EXTURL: [% constants.FIELD_TYPE_EXTURL %],
FIELD_TYPE_BUG_ID_REV: [% constants.FIELD_TYPE_BUG_ID_REV %]
};
[% END %]
@ -108,7 +109,7 @@ var constants = {
[% field_types.${field.type} | html %]
[% ELSE %]
<select id="type" name="type" onchange="onChangeType()">
[% FOREACH type = field_types.keys %]
[% FOREACH type = field_types.sort %]
[% NEXT IF type == constants.FIELD_TYPE_UNKNOWN %]
<option value="[% type | html %]">[% field_types.$type | html %]</option>
[% END %]
@ -183,7 +184,7 @@ var constants = {
</tr>
[% END %]
[% IF field.is_select || !field.id %]
<tr valign="top">
<tr valign="top" id="value_field_row">
<th colspan="2" align="left"><label for="value_field_id">
Field that controls the values that appear in this field:
</label></th>
@ -202,6 +203,27 @@ var constants = {
</td>
</tr>
[% END %]
[% IF field.type == constants.FIELD_TYPE_BUG_ID_REV || !field.id %]
<tr valign="top" id="bug_id_rev_row">
<th colspan="2" align="left"><label for="bug_id_rev_value_field_id">
Direct Bug ID field for this reverse one:
</label></th>
<td colspan="2">
[%# Duplicate name will be cleared by JS on creation form %]
<select style="width: 400px" name="value_field_id" id="bug_id_rev_value_field_id">
<option value="">---</option>
[% FOREACH sel_field = Bugzilla.get_fields({ custom => 1, type => constants.FIELD_TYPE_BUG_ID }) %]
[% NEXT IF sel_field.id == field.id %]
<option value="[% sel_field.id | html %]"
[% ' selected="selected"' IF sel_field.id == field.value_field.id %]>
[% sel_field.description | html %]
([% sel_field.name | html %])
</option>
[% END %]
</select>
</td>
</tr>
[% END %]
[% IF field.visibility_field %]
<tr valign="top" id="visibility_value_row">
<th colspan="2" align="left"><label for="visibility_value_id">

View File

@ -544,6 +544,20 @@
is not the right type of field.
[% END %]
[% BLOCK error_direct_field_needed_for_reverse %]
[% title = "Invalid Direct Field selected" %]
Each field of type "[% lc_messages.field_types.${constants.FIELD_TYPE_BUG_ID_REV} %]" must correspond
to one, and only one field of type "[% lc_messages.field_types.${constants.FIELD_TYPE_BUG_ID} %]" and
represent its "reverse relation". For example, it may be "Internal Bugs" for the corresponding
"External Bug" field.
[% END %]
[% BLOCK error_duplicate_reverse_field %]
[% title = "Duplicate Reverse Field" %]
It is prohibited to create more than one field of type "[% lc_messages.field_types.${constants.FIELD_TYPE_BUG_ID_REV} %]"
corresponding to a single "[% lc_messages.field_types.${constants.FIELD_TYPE_BUG_ID} %]" type field.
[% END %]
[% BLOCK error_field_type_mismatch %]
Cannot seem to handle <code>[% field FILTER html %]</code>
and <code>[% type FILTER html %]</code> together.