"Large Text Box (separate table)" field type

beta
Vitaliy Filippov 2018-03-22 20:43:02 +03:00
parent 65e825d471
commit a1e873904f
10 changed files with 127 additions and 30 deletions

View File

@ -106,8 +106,13 @@ sub DB_COLUMNS
# FIXME kill op_sys and rep_platform completely, make them custom fields # FIXME kill op_sys and rep_platform completely, make them custom fields
push @columns, 'op_sys' if Bugzilla->get_field('op_sys')->enabled; push @columns, 'op_sys' if Bugzilla->get_field('op_sys')->enabled;
push @columns, 'rep_platform' if Bugzilla->get_field('rep_platform')->enabled; push @columns, 'rep_platform' if Bugzilla->get_field('rep_platform')->enabled;
push @columns, map { $_->name } push @columns,
grep { $_->type != FIELD_TYPE_MULTI_SELECT && $_->type != FIELD_TYPE_BUG_ID_REV } map { $_->name }
grep {
$_->type != FIELD_TYPE_MULTI_SELECT &&
$_->type != FIELD_TYPE_EAV_TEXTAREA &&
$_->type != FIELD_TYPE_BUG_ID_REV
}
Bugzilla->active_custom_fields; Bugzilla->active_custom_fields;
Bugzilla::Hook::process('bug_columns', { columns => \@columns }); Bugzilla::Hook::process('bug_columns', { columns => \@columns });
@ -162,6 +167,7 @@ use constant CUSTOM_FIELD_VALIDATORS => {
FIELD_TYPE_BUG_ID_REV() => \&_set_bugid_rev_field, FIELD_TYPE_BUG_ID_REV() => \&_set_bugid_rev_field,
FIELD_TYPE_BUG_URLS() => \&_set_default_field, FIELD_TYPE_BUG_URLS() => \&_set_default_field,
FIELD_TYPE_NUMERIC() => \&_set_numeric_field, FIELD_TYPE_NUMERIC() => \&_set_numeric_field,
FIELD_TYPE_EAV_TEXTAREA() => \&_set_default_field,
}; };
sub SETTERS sub SETTERS
@ -576,6 +582,9 @@ sub update
# Insert the values into the multiselect value tables # Insert the values into the multiselect value tables
$self->save_multiselects($changes); $self->save_multiselects($changes);
# Insert the values into satellite value tables
$self->save_eavs($changes);
# Save reversed bug_id fields # Save reversed bug_id fields
$self->save_reverse_bugid_fields($changes); $self->save_reverse_bugid_fields($changes);
@ -932,6 +941,7 @@ sub check_dependent_fields
} }
# Check other fields for empty values # Check other fields for empty values
elsif (!$self->{$fn} || ($field_obj->type == FIELD_TYPE_FREETEXT || elsif (!$self->{$fn} || ($field_obj->type == FIELD_TYPE_FREETEXT ||
$field_obj->type == FIELD_TYPE_EAV_TEXTAREA ||
$field_obj->type == FIELD_TYPE_TEXTAREA) && $self->{$fn} =~ /^\s*$/so) $field_obj->type == FIELD_TYPE_TEXTAREA) && $self->{$fn} =~ /^\s*$/so)
{ {
my $nullable = $field_obj->check_is_nullable($self); my $nullable = $field_obj->check_is_nullable($self);
@ -945,6 +955,7 @@ sub check_dependent_fields
} }
} }
if (!$nullable && (!$self->{$fn} || ($field_obj->type == FIELD_TYPE_FREETEXT || if (!$nullable && (!$self->{$fn} || ($field_obj->type == FIELD_TYPE_FREETEXT ||
$field_obj->type == FIELD_TYPE_EAV_TEXTAREA ||
$field_obj->type == FIELD_TYPE_TEXTAREA) && $self->{$fn} =~ /^\s*$/so)) $field_obj->type == FIELD_TYPE_TEXTAREA) && $self->{$fn} =~ /^\s*$/so))
{ {
ThrowUserError('field_not_nullable', { field => $field_obj }); ThrowUserError('field_not_nullable', { field => $field_obj });
@ -1457,6 +1468,31 @@ sub save_multiselects
} }
} }
sub save_eavs
{
my ($self, $changes) = @_;
my @eavs = Bugzilla->get_fields({ obsolete => 0, type => FIELD_TYPE_EAV_TEXTAREA });
foreach my $field (@eavs)
{
my $name = $field->name;
if (defined $self->{$name})
{
my $old = $self->{_old_self} && $self->{_old_self}->$name || '';
my $v = $self->{$name};
if ($v ne $old)
{
Bugzilla->dbh->do("DELETE FROM bug_$name WHERE bug_id=?", undef, $self->id);
if ($v ne '')
{
Bugzilla->dbh->do("INSERT INTO bug_$name (bug_id, value) VALUES (?, ?)", undef, $self->id, $v);
}
$changes->{$name} = [ $old, $v ];
}
}
}
}
sub save_see_also sub save_see_also
{ {
my ($self, $changes) = @_; my ($self, $changes) = @_;
@ -3652,7 +3688,9 @@ sub GetBugActivity
{ {
my $change = $operations[$i]{changes}[$j]; my $change = $operations[$i]{changes}[$j];
my $field = Bugzilla->get_field($change->{fieldname}); my $field = Bugzilla->get_field($change->{fieldname});
if ($change->{fieldname} eq 'longdesc' || $field->{type} eq FIELD_TYPE_TEXTAREA) if ($change->{fieldname} eq 'longdesc' ||
$field->{type} == FIELD_TYPE_TEXTAREA ||
$field->{type} == FIELD_TYPE_EAV_TEXTAREA)
{ {
my $diff = Bugzilla::Diff->new($change->{removed}, $change->{added})->get_table; my $diff = Bugzilla::Diff->new($change->{removed}, $change->{added})->get_table;
if (!@$diff) if (!@$diff)
@ -4312,7 +4350,14 @@ sub get_value
elsif ($field->type == FIELD_TYPE_BUG_ID_REV) elsif ($field->type == FIELD_TYPE_BUG_ID_REV)
{ {
$self->{$attr} ||= Bugzilla->dbh->selectcol_arrayref( $self->{$attr} ||= Bugzilla->dbh->selectcol_arrayref(
"SELECT bug_id FROM bugs WHERE ".$field->value_field->name." = ".$self->id "SELECT bug_id FROM bugs WHERE ".$field->value_field->name." = ?", undef, $self->id
);
return $self->{$attr};
}
elsif ($field->type == FIELD_TYPE_EAV_TEXTAREA)
{
($self->{$attr}) = Bugzilla->dbh->selectrow_array(
"SELECT value FROM bug_$attr WHERE bug_id=?", undef, $self->id
); );
return $self->{$attr}; return $self->{$attr};
} }
@ -4338,7 +4383,7 @@ sub fields
map { $_->name } Bugzilla->get_fields({ map { $_->name } Bugzilla->get_fields({
obsolete => 0, obsolete => 0,
custom => 1, custom => 1,
type => [ FIELD_TYPE_MULTI_SELECT, FIELD_TYPE_BUG_ID_REV ], type => [ FIELD_TYPE_MULTI_SELECT, FIELD_TYPE_EAV_TEXTAREA, FIELD_TYPE_BUG_ID_REV ],
}), }),
); );
Bugzilla::Hook::process('bug_fields', { fields => \@fields }); Bugzilla::Hook::process('bug_fields', { fields => \@fields });
@ -4363,7 +4408,7 @@ sub _validate_attribute
# every DB column may be returned via an autoloaded accessor # every DB column may be returned via an autoloaded accessor
(map { $_ => 1 } Bugzilla::Bug->DB_COLUMNS), (map { $_ => 1 } Bugzilla::Bug->DB_COLUMNS),
# multiselect, bug_id_rev fields # multiselect, bug_id_rev fields
(map { $_->name => 1 } Bugzilla->get_fields({ type => [ FIELD_TYPE_MULTI_SELECT, FIELD_TYPE_BUG_ID_REV ] })), (map { $_->name => 1 } Bugzilla->get_fields({ type => [ FIELD_TYPE_MULTI_SELECT, FIELD_TYPE_EAV_TEXTAREA, FIELD_TYPE_BUG_ID_REV ] })),
# get_object accessors # get_object accessors
(map { $_->name.'_obj' => 1 } Bugzilla->get_fields({ type => [ FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT ] })), (map { $_->name.'_obj' => 1 } Bugzilla->get_fields({ type => [ FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT ] })),
}; };

View File

@ -129,6 +129,8 @@ use Cwd qw(abs_path);
FIELD_TYPE_NUMERIC FIELD_TYPE_NUMERIC
FIELD_TYPE_EXTURL FIELD_TYPE_EXTURL
FIELD_TYPE_BUG_ID_REV FIELD_TYPE_BUG_ID_REV
FIELD_TYPE_EAV_TEXTAREA
FIELD_TYPE__MAX
FLAG_VISIBLE FLAG_VISIBLE
FLAG_NULLABLE FLAG_NULLABLE
@ -392,6 +394,8 @@ use constant FIELD_TYPE_KEYWORDS => 8;
use constant FIELD_TYPE_NUMERIC => 30; use constant FIELD_TYPE_NUMERIC => 30;
use constant FIELD_TYPE_EXTURL => 31; use constant FIELD_TYPE_EXTURL => 31;
use constant FIELD_TYPE_BUG_ID_REV => 32; use constant FIELD_TYPE_BUG_ID_REV => 32;
use constant FIELD_TYPE_EAV_TEXTAREA => 33;
use constant FIELD_TYPE__MAX => 33;
use constant FLAG_VISIBLE => 0; use constant FLAG_VISIBLE => 0;
use constant FLAG_NULLABLE => -1; use constant FLAG_NULLABLE => -1;

View File

@ -816,12 +816,18 @@ sub _bz_add_field_table {
$self->bz_add_table($name); $self->bz_add_table($name);
} }
sub bz_add_field_tables { sub bz_add_field_tables
{
my ($self, $field) = @_; my ($self, $field) = @_;
if ($field->type == FIELD_TYPE_MULTI_SELECT ||
$self->_bz_add_field_table($field->name, $field->type == FIELD_TYPE_SINGLE_SELECT)
$self->_bz_schema->FIELD_TABLE_SCHEMA, $field->type); {
if ($field->type == FIELD_TYPE_MULTI_SELECT) { $self->_bz_add_field_table(
$field->name, $self->_bz_schema->FIELD_TABLE_SCHEMA, $field->type
);
}
if ($field->type == FIELD_TYPE_MULTI_SELECT)
{
my $ms_table = "bug_" . $field->name; my $ms_table = "bug_" . $field->name;
$self->_bz_add_field_table($ms_table, $self->_bz_add_field_table($ms_table,
$self->_bz_schema->MULTI_SELECT_VALUE_TABLE); $self->_bz_schema->MULTI_SELECT_VALUE_TABLE);
@ -832,14 +838,27 @@ sub bz_add_field_tables {
$self->bz_add_fk($ms_table, 'value_id', {TABLE => $field->name, $self->bz_add_fk($ms_table, 'value_id', {TABLE => $field->name,
COLUMN => 'id'}); COLUMN => 'id'});
} }
elsif ($field->type == FIELD_TYPE_EAV_TEXTAREA)
{
my $ms_table = "bug_" . $field->name;
$self->_bz_add_field_table($ms_table, $self->_bz_schema->EAV_TEXTAREA_VALUE_TABLE);
$self->bz_add_fk($ms_table, 'bug_id', {TABLE => 'bugs', COLUMN => 'bug_id', DELETE => 'CASCADE'});
}
} }
sub bz_drop_field_tables { sub bz_drop_field_tables
{
my ($self, $field) = @_; my ($self, $field) = @_;
if ($field->type == FIELD_TYPE_MULTI_SELECT) { if ($field->type == FIELD_TYPE_MULTI_SELECT ||
$field->type == FIELD_TYPE_EAV_TEXTAREA)
{
$self->bz_drop_table('bug_' . $field->name); $self->bz_drop_table('bug_' . $field->name);
} }
$self->bz_drop_table($field->name); if ($field->type == FIELD_TYPE_MULTI_SELECT ||
$field->type == FIELD_TYPE_SINGLE_SELECT)
{
$self->bz_drop_table($field->name);
}
} }
sub bz_drop_column sub bz_drop_column

View File

@ -1326,6 +1326,15 @@ use constant MULTI_SELECT_VALUE_TABLE => {
bug_id_idx => {FIELDS => [qw(bug_id value_id)], TYPE => 'UNIQUE'}, bug_id_idx => {FIELDS => [qw(bug_id value_id)], TYPE => 'UNIQUE'},
], ],
}; };
use constant EAV_TEXTAREA_VALUE_TABLE => {
FIELDS => [
bug_id => {TYPE => 'INT4', NOTNULL => 1},
value => {TYPE => 'MEDIUMTEXT', NOTNULL => 1, DEFAULT => "''"},
],
INDEXES => [
bug_id_idx => {FIELDS => [qw(bug_id)], TYPE => 'UNIQUE'},
],
};
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------

View File

@ -306,7 +306,7 @@ sub _check_type
# higher field type is added. # higher field type is added.
if (!detaint_natural($type) || $type <= FIELD_TYPE_UNKNOWN || if (!detaint_natural($type) || $type <= FIELD_TYPE_UNKNOWN ||
$type > FIELD_TYPE_KEYWORDS && $type < FIELD_TYPE_NUMERIC || $type > FIELD_TYPE_KEYWORDS && $type < FIELD_TYPE_NUMERIC ||
$type > FIELD_TYPE_BUG_ID_REV) $type > FIELD_TYPE__MAX)
{ {
ThrowCodeError('invalid_customfield_type', { type => $saved_type }); ThrowCodeError('invalid_customfield_type', { type => $saved_type });
} }
@ -893,11 +893,8 @@ sub remove_from_db
$dbh->bz_drop_column('bugs', $name); $dbh->bz_drop_column('bugs', $name);
} }
if ($self->is_select) # Delete the table that holds the legal values for this field.
{ $dbh->bz_drop_field_tables($self);
# Delete the table that holds the legal values for this field.
$dbh->bz_drop_field_tables($self);
}
$self->set_visibility_values(undef); $self->set_visibility_values(undef);
$self->set_null_visibility_values(undef); $self->set_null_visibility_values(undef);
@ -1278,13 +1275,8 @@ sub create
# Create the database column that stores the data for this field. # Create the database column that stores the data for this field.
$dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type}); $dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type});
} }
# Create the table that holds the legal values for this field.
if ($obj->is_select) $dbh->bz_add_field_tables($obj);
{
# Create the table that holds the legal values for this field.
$dbh->bz_add_field_tables($obj);
}
# Add foreign keys # Add foreign keys
if ($type == FIELD_TYPE_SINGLE_SELECT) if ($type == FIELD_TYPE_SINGLE_SELECT)
{ {

View File

@ -77,6 +77,7 @@ $Bugzilla::messages->{en} = {
FIELD_TYPE_NUMERIC() => 'Numeric', FIELD_TYPE_NUMERIC() => 'Numeric',
FIELD_TYPE_EXTURL() => 'External URL', FIELD_TYPE_EXTURL() => 'External URL',
FIELD_TYPE_BUG_ID_REV() => $terms->{Bug}.' ID reverse', FIELD_TYPE_BUG_ID_REV() => $terms->{Bug}.' ID reverse',
FIELD_TYPE_EAV_TEXTAREA() => 'Large Text Box (separate table)',
}, },
control_options => { control_options => {
CONTROLMAPNA() => 'NA', CONTROLMAPNA() => 'NA',

View File

@ -616,6 +616,12 @@ sub STATIC_COLUMNS
" FROM ".$type->REL_TABLE.", $t WHERE $t.".$type->ID_FIELD."=".$type->REL_TABLE.".value_id". " FROM ".$type->REL_TABLE.", $t WHERE $t.".$type->ID_FIELD."=".$type->REL_TABLE.".value_id".
" AND ".$type->REL_TABLE.".bug_id=bugs.bug_id)"; " AND ".$type->REL_TABLE.".bug_id=bugs.bug_id)";
} }
elsif ($field->type == FIELD_TYPE_EAV_TEXTAREA)
{
my $t = "bug_".$field->name;
$columns->{$id}->{name} = "$t.value";
$columns->{$id}->{joins} = [ "LEFT JOIN $t ON $t.bug_id=bugs.bug_id" ];
}
elsif ($bug_columns->{$id}) elsif ($bug_columns->{$id})
{ {
$columns->{$id}->{name} ||= "bugs.$id"; $columns->{$id}->{name} ||= "bugs.$id";
@ -701,6 +707,17 @@ sub STATIC_COLUMNS
sortkey => 1, sortkey => 1,
}; };
} }
elsif ($subfield->type == FIELD_TYPE_MULTI_SELECT)
{
my $t = 'bug_'.$subfield->name;
$columns->{$id.'_'.$subid} = {
name => "bugs_$id"."_$t.value",
title => $field->description . ' ' . $subfield->description,
joins => [ @$join, "LEFT JOIN $t bugs_$id"."_$t ON bugs_$id"."_$t.bug_id=bugs_$id.bug_id" ],
subid => $subid,
sortkey => 1,
};
}
} }
} }

View File

@ -126,7 +126,7 @@
<option value="[% v.id %]"[% ' selected="selected"' IF cur_default.${v.id} %]>[% v.name | html %]</option> <option value="[% v.id %]"[% ' selected="selected"' IF cur_default.${v.id} %]>[% v.name | html %]</option>
[% END %] [% END %]
</select> </select>
[% ELSIF f.type == constants.FIELD_TYPE_TEXTAREA %] [% ELSIF f.type == constants.FIELD_TYPE_TEXTAREA || f.type == constants.FIELD_TYPE_EAV_TEXTAREA %]
<textarea cols="50" rows="5" name="default_[% f.name | html %]" id="default_[% f.name | html %]">[% f.get_default_value(this_value.id) | html %]</textarea> <textarea cols="50" rows="5" name="default_[% f.name | html %]" id="default_[% f.name | html %]">[% f.get_default_value(this_value.id) | html %]</textarea>
[% ELSE %] [% ELSE %]
<input type="text" name="default_[% f.name | html %]" id="default_[% f.name | html %]" value="[% f.get_default_value(this_value.id) | html %]" /> <input type="text" name="default_[% f.name | html %]" id="default_[% f.name | html %]" value="[% f.get_default_value(this_value.id) | html %]" />

View File

@ -226,7 +226,7 @@ var close_status_array = [
[% END %] [% END %]
[% INCLUDE custom_fields style = "width: 40em" [% INCLUDE custom_fields style = "width: 40em"
cf = Bugzilla.active_custom_fields({ 'type' => constants.FIELD_TYPE_TEXTAREA }) %] cf = Bugzilla.active_custom_fields({ 'type' => [ constants.FIELD_TYPE_TEXTAREA, constants.FIELD_TYPE_EAV_TEXTAREA ] }) %]
[% INCLUDE custom_fields style = "min-width: 20em; max-width: 40em" [% INCLUDE custom_fields style = "min-width: 20em; max-width: 40em"
cf = Bugzilla.active_custom_fields({ 'type' => constants.FIELD_TYPE_MULTI_SELECT }) %] cf = Bugzilla.active_custom_fields({ 'type' => constants.FIELD_TYPE_MULTI_SELECT }) %]

View File

@ -55,6 +55,7 @@
bug.id && field.type != constants.FIELD_TYPE_BUG_ID_REV && bug.id && field.type != constants.FIELD_TYPE_BUG_ID_REV &&
field.type != constants.FIELD_TYPE_MULTI_SELECT && field.type != constants.FIELD_TYPE_MULTI_SELECT &&
field.type != constants.FIELD_TYPE_TEXTAREA && field.type != constants.FIELD_TYPE_TEXTAREA &&
field.type != constants.FIELD_TYPE_EAV_TEXTAREA &&
field.type != constants.FIELD_TYPE_BUG_URLS && field.type != constants.FIELD_TYPE_BUG_URLS &&
field.type != constants.FIELD_TYPE_BUG_ID %] field.type != constants.FIELD_TYPE_BUG_ID %]
@ -259,6 +260,15 @@
cols = 30 cols = 30
defaultcontent = value defaultcontent = value
tabindex = tabindex %] tabindex = tabindex %]
[% CASE constants.FIELD_TYPE_EAV_TEXTAREA %]
[% INCLUDE global/textarea.html.tmpl
id = field.name
name = field.name
minrows = 4
maxrows = 8
cols = 30
defaultcontent = value
tabindex = tabindex %]
[% CASE constants.FIELD_TYPE_BUG_URLS %] [% CASE constants.FIELD_TYPE_BUG_URLS %]
[% '<ul class="bug_urls">' IF value.size %] [% '<ul class="bug_urls">' IF value.size %]
[% FOREACH url = value %] [% FOREACH url = value %]
@ -292,7 +302,7 @@
[% IF show_search_link %] [% IF show_search_link %]
</td><td style="padding-left: 5px">[% PROCESS search_link %](search)</a></td></tr></table> </td><td style="padding-left: 5px">[% PROCESS search_link %](search)</a></td></tr></table>
[% END %] [% END %]
[% ELSIF field.type == constants.FIELD_TYPE_TEXTAREA %] [% ELSIF field.type == constants.FIELD_TYPE_TEXTAREA || field.type == constants.FIELD_TYPE_EAV_TEXTAREA %]
<div class="uneditable_textarea">[% value | html | wrap_comment %]</div> <div class="uneditable_textarea">[% value | html | wrap_comment %]</div>
[% ELSIF field.type == constants.FIELD_TYPE_BUG_ID %] [% ELSIF field.type == constants.FIELD_TYPE_BUG_ID %]
[% IF bug.${field.name} %] [% IF bug.${field.name} %]