From a1e873904f8284a6aaa7e5a3dfbf56c85490dac7 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Thu, 22 Mar 2018 20:43:02 +0300 Subject: [PATCH] "Large Text Box (separate table)" field type --- Bugzilla/Bug.pm | 57 +++++++++++++++++-- Bugzilla/Constants.pm | 4 ++ Bugzilla/DB.pm | 35 +++++++++--- Bugzilla/DB/Schema.pm | 9 +++ Bugzilla/Field.pm | 18 ++---- Bugzilla/Language/en.pm | 1 + Bugzilla/Search.pm | 17 ++++++ .../fieldvalues/control-list-common.html.tmpl | 2 +- .../en/default/bug/create/create.html.tmpl | 2 +- template/en/default/bug/field.html.tmpl | 12 +++- 10 files changed, 127 insertions(+), 30 deletions(-) diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 04af4e8b7..f07b5a0d8 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -106,8 +106,13 @@ sub DB_COLUMNS # 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, 'rep_platform' if Bugzilla->get_field('rep_platform')->enabled; - push @columns, map { $_->name } - grep { $_->type != FIELD_TYPE_MULTI_SELECT && $_->type != FIELD_TYPE_BUG_ID_REV } + push @columns, + map { $_->name } + grep { + $_->type != FIELD_TYPE_MULTI_SELECT && + $_->type != FIELD_TYPE_EAV_TEXTAREA && + $_->type != FIELD_TYPE_BUG_ID_REV + } Bugzilla->active_custom_fields; 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_URLS() => \&_set_default_field, FIELD_TYPE_NUMERIC() => \&_set_numeric_field, + FIELD_TYPE_EAV_TEXTAREA() => \&_set_default_field, }; sub SETTERS @@ -576,6 +582,9 @@ sub update # Insert the values into the multiselect value tables $self->save_multiselects($changes); + # Insert the values into satellite value tables + $self->save_eavs($changes); + # Save reversed bug_id fields $self->save_reverse_bugid_fields($changes); @@ -932,6 +941,7 @@ sub check_dependent_fields } # Check other fields for empty values 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) { 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 || + $field_obj->type == FIELD_TYPE_EAV_TEXTAREA || $field_obj->type == FIELD_TYPE_TEXTAREA) && $self->{$fn} =~ /^\s*$/so)) { 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 { my ($self, $changes) = @_; @@ -3652,7 +3688,9 @@ sub GetBugActivity { my $change = $operations[$i]{changes}[$j]; 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; if (!@$diff) @@ -4312,7 +4350,14 @@ sub get_value 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 + "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}; } @@ -4338,7 +4383,7 @@ sub fields map { $_->name } Bugzilla->get_fields({ obsolete => 0, 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 }); @@ -4363,7 +4408,7 @@ sub _validate_attribute # every DB column may be returned via an autoloaded accessor (map { $_ => 1 } Bugzilla::Bug->DB_COLUMNS), # 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 (map { $_->name.'_obj' => 1 } Bugzilla->get_fields({ type => [ FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT ] })), }; diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index ba92ad906..6903e4c36 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -129,6 +129,8 @@ use Cwd qw(abs_path); FIELD_TYPE_NUMERIC FIELD_TYPE_EXTURL FIELD_TYPE_BUG_ID_REV + FIELD_TYPE_EAV_TEXTAREA + FIELD_TYPE__MAX FLAG_VISIBLE FLAG_NULLABLE @@ -392,6 +394,8 @@ 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 FIELD_TYPE_EAV_TEXTAREA => 33; +use constant FIELD_TYPE__MAX => 33; use constant FLAG_VISIBLE => 0; use constant FLAG_NULLABLE => -1; diff --git a/Bugzilla/DB.pm b/Bugzilla/DB.pm index c1390c268..247260a98 100644 --- a/Bugzilla/DB.pm +++ b/Bugzilla/DB.pm @@ -816,12 +816,18 @@ sub _bz_add_field_table { $self->bz_add_table($name); } -sub bz_add_field_tables { +sub bz_add_field_tables +{ my ($self, $field) = @_; - - $self->_bz_add_field_table($field->name, - $self->_bz_schema->FIELD_TABLE_SCHEMA, $field->type); - if ($field->type == FIELD_TYPE_MULTI_SELECT) { + if ($field->type == FIELD_TYPE_MULTI_SELECT || + $field->type == FIELD_TYPE_SINGLE_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; $self->_bz_add_field_table($ms_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, 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) = @_; - 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($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 diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index 05bcd99f8..8a5bb2bf1 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -1326,6 +1326,15 @@ use constant MULTI_SELECT_VALUE_TABLE => { 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'}, + ], +}; #-------------------------------------------------------------------------- diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 426a272cc..2339eaff3 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -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_BUG_ID_REV) + $type > FIELD_TYPE__MAX) { ThrowCodeError('invalid_customfield_type', { type => $saved_type }); } @@ -893,11 +893,8 @@ sub remove_from_db $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_null_visibility_values(undef); @@ -1278,13 +1275,8 @@ sub create # Create the database column that stores the data for this field. $dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type}); } - - if ($obj->is_select) - { - # Create the table that holds the legal values for this field. - $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 if ($type == FIELD_TYPE_SINGLE_SELECT) { diff --git a/Bugzilla/Language/en.pm b/Bugzilla/Language/en.pm index f19e54360..35f48fe71 100644 --- a/Bugzilla/Language/en.pm +++ b/Bugzilla/Language/en.pm @@ -77,6 +77,7 @@ $Bugzilla::messages->{en} = { FIELD_TYPE_NUMERIC() => 'Numeric', FIELD_TYPE_EXTURL() => 'External URL', FIELD_TYPE_BUG_ID_REV() => $terms->{Bug}.' ID reverse', + FIELD_TYPE_EAV_TEXTAREA() => 'Large Text Box (separate table)', }, control_options => { CONTROLMAPNA() => 'NA', diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index 3fbcc5ba9..ce85ec4e7 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -616,6 +616,12 @@ sub STATIC_COLUMNS " FROM ".$type->REL_TABLE.", $t WHERE $t.".$type->ID_FIELD."=".$type->REL_TABLE.".value_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}) { $columns->{$id}->{name} ||= "bugs.$id"; @@ -701,6 +707,17 @@ sub STATIC_COLUMNS 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, + }; + } } } diff --git a/template/en/default/admin/fieldvalues/control-list-common.html.tmpl b/template/en/default/admin/fieldvalues/control-list-common.html.tmpl index b5b0bdaf8..3d0f7e36c 100644 --- a/template/en/default/admin/fieldvalues/control-list-common.html.tmpl +++ b/template/en/default/admin/fieldvalues/control-list-common.html.tmpl @@ -126,7 +126,7 @@ [% END %] - [% ELSIF f.type == constants.FIELD_TYPE_TEXTAREA %] + [% ELSIF f.type == constants.FIELD_TYPE_TEXTAREA || f.type == constants.FIELD_TYPE_EAV_TEXTAREA %] [% ELSE %] diff --git a/template/en/default/bug/create/create.html.tmpl b/template/en/default/bug/create/create.html.tmpl index 8630c9db5..27459bd13 100644 --- a/template/en/default/bug/create/create.html.tmpl +++ b/template/en/default/bug/create/create.html.tmpl @@ -226,7 +226,7 @@ var close_status_array = [ [% END %] [% 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" cf = Bugzilla.active_custom_fields({ 'type' => constants.FIELD_TYPE_MULTI_SELECT }) %] diff --git a/template/en/default/bug/field.html.tmpl b/template/en/default/bug/field.html.tmpl index ee0310fe5..6363a6c06 100644 --- a/template/en/default/bug/field.html.tmpl +++ b/template/en/default/bug/field.html.tmpl @@ -55,6 +55,7 @@ bug.id && field.type != constants.FIELD_TYPE_BUG_ID_REV && field.type != constants.FIELD_TYPE_MULTI_SELECT && 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_ID %] @@ -259,6 +260,15 @@ cols = 30 defaultcontent = value 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 %] [% '