1049 lines
29 KiB
Perl
1049 lines
29 KiB
Perl
# --
|
|
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
|
# --
|
|
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
# the enclosed file COPYING for license information (GPL). If you
|
|
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
|
# --
|
|
|
|
package Kernel::System::DynamicField::Driver::Multiselect;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Kernel::System::VariableCheck qw(:all);
|
|
|
|
use parent qw(Kernel::System::DynamicField::Driver::BaseSelect);
|
|
|
|
our @ObjectDependencies = (
|
|
'Kernel::Config',
|
|
'Kernel::System::DynamicFieldValue',
|
|
'Kernel::System::Log',
|
|
'Kernel::System::Main',
|
|
);
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::System::DynamicField::Driver::Multiselect
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
DynamicFields Multiselect Driver delegate
|
|
|
|
=head1 PUBLIC INTERFACE
|
|
|
|
This module implements the public interface of L<Kernel::System::DynamicField::Backend>.
|
|
Please look there for a detailed reference of the functions.
|
|
|
|
=head2 new()
|
|
|
|
usually, you want to create an instance of this
|
|
by using Kernel::System::DynamicField::Backend->new();
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
# allocate new hash for object
|
|
my $Self = {};
|
|
bless( $Self, $Type );
|
|
|
|
# set field behaviors
|
|
$Self->{Behaviors} = {
|
|
'IsACLReducible' => 1,
|
|
'IsNotificationEventCondition' => 1,
|
|
'IsSortable' => 0,
|
|
'IsFiltrable' => 0,
|
|
'IsStatsCondition' => 1,
|
|
'IsCustomerInterfaceCapable' => 1,
|
|
'IsLikeOperatorCapable' => 1,
|
|
};
|
|
|
|
# get the Dynamic Field Backend custom extensions
|
|
my $DynamicFieldDriverExtensions
|
|
= $Kernel::OM->Get('Kernel::Config')->Get('DynamicFields::Extension::Driver::Multiselect');
|
|
|
|
EXTENSION:
|
|
for my $ExtensionKey ( sort keys %{$DynamicFieldDriverExtensions} ) {
|
|
|
|
# skip invalid extensions
|
|
next EXTENSION if !IsHashRefWithData( $DynamicFieldDriverExtensions->{$ExtensionKey} );
|
|
|
|
# create a extension config shortcut
|
|
my $Extension = $DynamicFieldDriverExtensions->{$ExtensionKey};
|
|
|
|
# check if extension has a new module
|
|
if ( $Extension->{Module} ) {
|
|
|
|
# check if module can be loaded
|
|
if (
|
|
!$Kernel::OM->Get('Kernel::System::Main')->RequireBaseClass( $Extension->{Module} )
|
|
)
|
|
{
|
|
die "Can't load dynamic fields backend module"
|
|
. " $Extension->{Module}! $@";
|
|
}
|
|
}
|
|
|
|
# check if extension contains more behaviors
|
|
if ( IsHashRefWithData( $Extension->{Behaviors} ) ) {
|
|
|
|
%{ $Self->{Behaviors} } = (
|
|
%{ $Self->{Behaviors} },
|
|
%{ $Extension->{Behaviors} }
|
|
);
|
|
}
|
|
}
|
|
|
|
return $Self;
|
|
}
|
|
|
|
sub ValueGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $DFValue = $Kernel::OM->Get('Kernel::System::DynamicFieldValue')->ValueGet(
|
|
FieldID => $Param{DynamicFieldConfig}->{ID},
|
|
ObjectID => $Param{ObjectID},
|
|
);
|
|
|
|
return if !$DFValue;
|
|
return if !IsArrayRefWithData($DFValue);
|
|
return if !IsHashRefWithData( $DFValue->[0] );
|
|
|
|
# extract real values
|
|
my @ReturnData;
|
|
for my $Item ( @{$DFValue} ) {
|
|
push @ReturnData, $Item->{ValueText};
|
|
}
|
|
|
|
return \@ReturnData;
|
|
}
|
|
|
|
sub ValueSet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check for valid possible values list
|
|
if ( !$Param{DynamicFieldConfig}->{Config}->{PossibleValues} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need PossibleValues in DynamicFieldConfig!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check value
|
|
my @Values;
|
|
if ( ref $Param{Value} eq 'ARRAY' ) {
|
|
@Values = @{ $Param{Value} };
|
|
}
|
|
else {
|
|
@Values = ( $Param{Value} );
|
|
}
|
|
|
|
# get dynamic field value object
|
|
my $DynamicFieldValueObject = $Kernel::OM->Get('Kernel::System::DynamicFieldValue');
|
|
|
|
my $Success;
|
|
if ( IsArrayRefWithData( \@Values ) ) {
|
|
|
|
# if there is at least one value to set, this means one or more values are selected,
|
|
# set those values!
|
|
my @ValueText;
|
|
for my $Item (@Values) {
|
|
push @ValueText, { ValueText => $Item };
|
|
}
|
|
|
|
$Success = $DynamicFieldValueObject->ValueSet(
|
|
FieldID => $Param{DynamicFieldConfig}->{ID},
|
|
ObjectID => $Param{ObjectID},
|
|
Value => \@ValueText,
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
else {
|
|
|
|
# otherwise no value was selected, then in fact this means that any value there should be
|
|
# deleted
|
|
$Success = $DynamicFieldValueObject->ValueDelete(
|
|
FieldID => $Param{DynamicFieldConfig}->{ID},
|
|
ObjectID => $Param{ObjectID},
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
return $Success;
|
|
}
|
|
|
|
sub ValueIsDifferent {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# special cases where the values are different but they should be reported as equals
|
|
if (
|
|
!defined $Param{Value1}
|
|
&& ref $Param{Value2} eq 'ARRAY'
|
|
&& !IsArrayRefWithData( $Param{Value2} )
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
if (
|
|
!defined $Param{Value2}
|
|
&& ref $Param{Value1} eq 'ARRAY'
|
|
&& !IsArrayRefWithData( $Param{Value1} )
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
# compare the results
|
|
return DataIsDifferent(
|
|
Data1 => \$Param{Value1},
|
|
Data2 => \$Param{Value2}
|
|
);
|
|
}
|
|
|
|
sub ValueValidate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check value
|
|
my @Values;
|
|
if ( IsArrayRefWithData( $Param{Value} ) ) {
|
|
@Values = @{ $Param{Value} };
|
|
}
|
|
else {
|
|
@Values = ( $Param{Value} );
|
|
}
|
|
|
|
# get dynamic field value object
|
|
my $DynamicFieldValueObject = $Kernel::OM->Get('Kernel::System::DynamicFieldValue');
|
|
|
|
my $Success;
|
|
for my $Item (@Values) {
|
|
|
|
$Success = $DynamicFieldValueObject->ValueValidate(
|
|
Value => {
|
|
ValueText => $Item,
|
|
},
|
|
UserID => $Param{UserID}
|
|
);
|
|
|
|
return if !$Success;
|
|
}
|
|
|
|
return $Success;
|
|
}
|
|
|
|
sub FieldValueValidate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# Check for valid possible values list.
|
|
if ( !IsHashRefWithData( $Param{DynamicFieldConfig}->{Config}->{PossibleValues} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need PossibleValues in Multiselect DynamicFieldConfig!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# Check for defined value.
|
|
if ( !defined $Param{Value} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need Value in Multiselect DynamicField!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# Check if value parameter exists in possible values config.
|
|
if ( length $Param{Value} ) {
|
|
my @Values;
|
|
if ( ref $Param{Value} eq 'ARRAY' ) {
|
|
@Values = @{ $Param{Value} };
|
|
}
|
|
else {
|
|
push @Values, $Param{Value};
|
|
}
|
|
|
|
for my $Value (@Values) {
|
|
return if !defined $Param{DynamicFieldConfig}->{Config}->{PossibleValues}->{$Value};
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub EditFieldRender {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# take config from field config
|
|
my $FieldConfig = $Param{DynamicFieldConfig}->{Config};
|
|
my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
|
|
my $FieldLabel = $Param{DynamicFieldConfig}->{Label};
|
|
|
|
my $Value;
|
|
|
|
# set the field value or default
|
|
if ( $Param{UseDefaultValue} ) {
|
|
$Value = ( defined $FieldConfig->{DefaultValue} ? $FieldConfig->{DefaultValue} : '' );
|
|
}
|
|
$Value = $Param{Value} // $Value;
|
|
|
|
# check if a value in a template (GenericAgent etc.)
|
|
# is configured for this dynamic field
|
|
if (
|
|
IsHashRefWithData( $Param{Template} )
|
|
&& defined $Param{Template}->{$FieldName}
|
|
)
|
|
{
|
|
$Value = $Param{Template}->{$FieldName};
|
|
}
|
|
|
|
# extract the dynamic field value from the web request
|
|
my $FieldValue = $Self->EditFieldValueGet(
|
|
%Param,
|
|
);
|
|
|
|
# set values from ParamObject if present
|
|
if ( IsArrayRefWithData($FieldValue) ) {
|
|
$Value = $FieldValue;
|
|
}
|
|
|
|
# check and set class if necessary
|
|
my $FieldClass = 'DynamicFieldText Modernize';
|
|
if ( defined $Param{Class} && $Param{Class} ne '' ) {
|
|
$FieldClass .= ' ' . $Param{Class};
|
|
}
|
|
|
|
# set field as mandatory
|
|
if ( $Param{Mandatory} ) {
|
|
$FieldClass .= ' Validate_Required';
|
|
}
|
|
|
|
# set error css class
|
|
if ( $Param{ServerError} ) {
|
|
$FieldClass .= ' ServerError';
|
|
}
|
|
|
|
# set TreeView class
|
|
if ( $FieldConfig->{TreeView} ) {
|
|
$FieldClass .= ' DynamicFieldWithTreeView';
|
|
}
|
|
|
|
# set PossibleValues, use PossibleValuesFilter if defined
|
|
my $PossibleValues = $Param{PossibleValuesFilter} // $Self->PossibleValuesGet(%Param);
|
|
|
|
# check value
|
|
my $SelectedValuesArrayRef;
|
|
if ( defined $Value ) {
|
|
if ( ref $Value eq 'ARRAY' ) {
|
|
$SelectedValuesArrayRef = $Value;
|
|
}
|
|
else {
|
|
$SelectedValuesArrayRef = [$Value];
|
|
}
|
|
}
|
|
|
|
my $DataValues = $Self->BuildSelectionDataGet(
|
|
DynamicFieldConfig => $Param{DynamicFieldConfig},
|
|
PossibleValues => $PossibleValues,
|
|
Value => $Value,
|
|
);
|
|
|
|
my $HTMLString = $Param{LayoutObject}->BuildSelection(
|
|
Data => $DataValues || {},
|
|
Name => $FieldName,
|
|
SelectedID => $SelectedValuesArrayRef,
|
|
Translation => $FieldConfig->{TranslatableValues} || 0,
|
|
Class => $FieldClass,
|
|
HTMLQuote => 1,
|
|
Multiple => 1,
|
|
);
|
|
|
|
if ( $FieldConfig->{TreeView} ) {
|
|
my $TreeSelectionMessage = $Param{LayoutObject}->{LanguageObject}->Translate("Show Tree Selection");
|
|
$HTMLString
|
|
.= ' <a href="#" title="'
|
|
. $TreeSelectionMessage
|
|
. '" class="ShowTreeSelection"><span>'
|
|
. $TreeSelectionMessage . '</span><i class="fa fa-sitemap"></i></a>';
|
|
}
|
|
|
|
if ( $Param{Mandatory} ) {
|
|
my $DivID = $FieldName . 'Error';
|
|
|
|
my $FieldRequiredMessage = $Param{LayoutObject}->{LanguageObject}->Translate("This field is required.");
|
|
|
|
# for client side validation
|
|
$HTMLString .= <<"EOF";
|
|
|
|
<div id="$DivID" class="TooltipErrorMessage">
|
|
<p>
|
|
$FieldRequiredMessage
|
|
</p>
|
|
</div>
|
|
EOF
|
|
}
|
|
|
|
if ( $Param{ServerError} ) {
|
|
|
|
my $ErrorMessage = $Param{ErrorMessage} || 'This field is required.';
|
|
$ErrorMessage = $Param{LayoutObject}->{LanguageObject}->Translate($ErrorMessage);
|
|
my $DivID = $FieldName . 'ServerError';
|
|
|
|
# for server side validation
|
|
$HTMLString .= <<"EOF";
|
|
|
|
<div id="$DivID" class="TooltipErrorMessage">
|
|
<p>
|
|
$ErrorMessage
|
|
</p>
|
|
</div>
|
|
EOF
|
|
}
|
|
|
|
if ( $Param{AJAXUpdate} ) {
|
|
|
|
my $FieldSelector = '#' . $FieldName;
|
|
|
|
my $FieldsToUpdate;
|
|
if ( IsArrayRefWithData( $Param{UpdatableFields} ) ) {
|
|
|
|
# Remove current field from updatable fields list
|
|
my @FieldsToUpdate = grep { $_ ne $FieldName } @{ $Param{UpdatableFields} };
|
|
|
|
# quote all fields, put commas in between them
|
|
$FieldsToUpdate = join( ', ', map {"'$_'"} @FieldsToUpdate );
|
|
}
|
|
|
|
# add js to call FormUpdate()
|
|
$Param{LayoutObject}->AddJSOnDocumentComplete( Code => <<"EOF");
|
|
\$('$FieldSelector').bind('change', function (Event) {
|
|
Core.AJAX.FormUpdate(\$(this).parents('form'), 'AJAXUpdate', '$FieldName', [ $FieldsToUpdate ]);
|
|
});
|
|
Core.App.Subscribe('Event.AJAX.FormUpdate.Callback', function(Data) {
|
|
var FieldName = '$FieldName';
|
|
if (Data[FieldName] && \$('#' + FieldName).hasClass('DynamicFieldWithTreeView')) {
|
|
Core.UI.TreeSelection.RestoreDynamicFieldTreeView(\$('#' + FieldName), Data[FieldName], '' , 1);
|
|
}
|
|
});
|
|
EOF
|
|
}
|
|
|
|
# call EditLabelRender on the common Driver
|
|
my $LabelString = $Self->EditLabelRender(
|
|
%Param,
|
|
Mandatory => $Param{Mandatory} || '0',
|
|
FieldName => $FieldName,
|
|
);
|
|
|
|
my $Data = {
|
|
Field => $HTMLString,
|
|
Label => $LabelString,
|
|
};
|
|
|
|
return $Data;
|
|
}
|
|
|
|
sub EditFieldValueGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
|
|
|
|
my $Value;
|
|
|
|
# check if there is a Template and retrieve the dynamic field value from there
|
|
if ( IsHashRefWithData( $Param{Template} ) && defined $Param{Template}->{$FieldName} ) {
|
|
$Value = $Param{Template}->{$FieldName};
|
|
}
|
|
|
|
# otherwise get dynamic field value from the web request
|
|
elsif (
|
|
defined $Param{ParamObject}
|
|
&& ref $Param{ParamObject} eq 'Kernel::System::Web::Request'
|
|
)
|
|
{
|
|
my @Data = $Param{ParamObject}->GetArray( Param => $FieldName );
|
|
|
|
# delete empty values (can happen if the user has selected the "-" entry)
|
|
my $Index = 0;
|
|
ITEM:
|
|
for my $Item ( sort @Data ) {
|
|
|
|
if ( !$Item ) {
|
|
splice( @Data, $Index, 1 );
|
|
next ITEM;
|
|
}
|
|
$Index++;
|
|
}
|
|
|
|
$Value = \@Data;
|
|
}
|
|
|
|
if ( defined $Param{ReturnTemplateStructure} && $Param{ReturnTemplateStructure} eq 1 ) {
|
|
return {
|
|
$FieldName => $Value,
|
|
};
|
|
}
|
|
|
|
# for this field the normal return an the ReturnValueStructure are the same
|
|
return $Value;
|
|
}
|
|
|
|
sub EditFieldValueValidate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# get the field value from the http request
|
|
my $Values = $Self->EditFieldValueGet(
|
|
DynamicFieldConfig => $Param{DynamicFieldConfig},
|
|
ParamObject => $Param{ParamObject},
|
|
|
|
# not necessary for this Driver but place it for consistency reasons
|
|
ReturnValueStructure => 1,
|
|
);
|
|
|
|
my $ServerError;
|
|
my $ErrorMessage;
|
|
|
|
# perform necessary validations
|
|
if ( $Param{Mandatory} && !IsArrayRefWithData($Values) ) {
|
|
return {
|
|
ServerError => 1,
|
|
};
|
|
}
|
|
else {
|
|
|
|
# get possible values list
|
|
my $PossibleValues = $Param{DynamicFieldConfig}->{Config}->{PossibleValues};
|
|
|
|
# overwrite possible values if PossibleValuesFilter
|
|
if ( defined $Param{PossibleValuesFilter} ) {
|
|
$PossibleValues = $Param{PossibleValuesFilter};
|
|
}
|
|
|
|
# validate if value is in possible values list (but let pass empty values)
|
|
for my $Item ( @{$Values} ) {
|
|
if ( !$PossibleValues->{$Item} ) {
|
|
$ServerError = 1;
|
|
$ErrorMessage = 'The field content is invalid';
|
|
}
|
|
}
|
|
}
|
|
|
|
# create resulting structure
|
|
my $Result = {
|
|
ServerError => $ServerError,
|
|
ErrorMessage => $ErrorMessage,
|
|
};
|
|
|
|
return $Result;
|
|
}
|
|
|
|
sub DisplayValueRender {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# set HTMLOutput as default if not specified
|
|
if ( !defined $Param{HTMLOutput} ) {
|
|
$Param{HTMLOutput} = 1;
|
|
}
|
|
|
|
# set Value and Title variables
|
|
my $Value = '';
|
|
my $Title = '';
|
|
my $ValueMaxChars = $Param{ValueMaxChars} || '';
|
|
my $TitleMaxChars = $Param{TitleMaxChars} || '';
|
|
|
|
# check value
|
|
my @Values;
|
|
if ( ref $Param{Value} eq 'ARRAY' ) {
|
|
@Values = @{ $Param{Value} };
|
|
}
|
|
else {
|
|
@Values = ( $Param{Value} );
|
|
}
|
|
|
|
# get real values
|
|
my $PossibleValues = $Param{DynamicFieldConfig}->{Config}->{PossibleValues};
|
|
my $TranslatableValues = $Param{DynamicFieldConfig}->{Config}->{TranslatableValues};
|
|
|
|
my @ReadableValues;
|
|
my @ReadableTitles;
|
|
|
|
my $ShowValueEllipsis;
|
|
my $ShowTitleEllipsis;
|
|
|
|
VALUEITEM:
|
|
for my $Item (@Values) {
|
|
next VALUEITEM if !$Item;
|
|
|
|
my $ReadableValue = $Item;
|
|
|
|
if ( $PossibleValues->{$Item} ) {
|
|
$ReadableValue = $PossibleValues->{$Item};
|
|
if ($TranslatableValues) {
|
|
$ReadableValue = $Param{LayoutObject}->{LanguageObject}->Translate($ReadableValue);
|
|
}
|
|
}
|
|
|
|
my $ReadableLength = length $ReadableValue;
|
|
|
|
# set title equal value
|
|
my $ReadableTitle = $ReadableValue;
|
|
|
|
# cut strings if needed
|
|
if ( $ValueMaxChars ne '' ) {
|
|
|
|
if ( length $ReadableValue > $ValueMaxChars ) {
|
|
$ShowValueEllipsis = 1;
|
|
}
|
|
$ReadableValue = substr $ReadableValue, 0, $ValueMaxChars;
|
|
|
|
# decrease the max parameter
|
|
$ValueMaxChars = $ValueMaxChars - $ReadableLength;
|
|
if ( $ValueMaxChars < 0 ) {
|
|
$ValueMaxChars = 0;
|
|
}
|
|
}
|
|
|
|
if ( $TitleMaxChars ne '' ) {
|
|
|
|
if ( length $ReadableTitle > $ValueMaxChars ) {
|
|
$ShowTitleEllipsis = 1;
|
|
}
|
|
$ReadableTitle = substr $ReadableTitle, 0, $TitleMaxChars;
|
|
|
|
# decrease the max parameter
|
|
$TitleMaxChars = $TitleMaxChars - $ReadableLength;
|
|
if ( $TitleMaxChars < 0 ) {
|
|
$TitleMaxChars = 0;
|
|
}
|
|
}
|
|
|
|
# HTMLOutput transformations
|
|
if ( $Param{HTMLOutput} ) {
|
|
|
|
$ReadableValue = $Param{LayoutObject}->Ascii2Html(
|
|
Text => $ReadableValue,
|
|
);
|
|
|
|
$ReadableTitle = $Param{LayoutObject}->Ascii2Html(
|
|
Text => $ReadableTitle,
|
|
);
|
|
}
|
|
|
|
if ( length $ReadableValue ) {
|
|
push @ReadableValues, $ReadableValue;
|
|
}
|
|
if ( length $ReadableTitle ) {
|
|
push @ReadableTitles, $ReadableTitle;
|
|
}
|
|
}
|
|
|
|
# get specific field settings
|
|
my $FieldConfig = $Kernel::OM->Get('Kernel::Config')->Get('DynamicFields::Driver')->{Multiselect} || {};
|
|
|
|
# set new line separator
|
|
my $ItemSeparator = $FieldConfig->{ItemSeparator} || ', ';
|
|
|
|
$Value = join( $ItemSeparator, @ReadableValues );
|
|
$Title = join( $ItemSeparator, @ReadableTitles );
|
|
|
|
if ($ShowValueEllipsis) {
|
|
$Value .= '...';
|
|
}
|
|
if ($ShowTitleEllipsis) {
|
|
$Title .= '...';
|
|
}
|
|
|
|
# this field type does not support the Link Feature
|
|
my $Link;
|
|
|
|
# create return structure
|
|
my $Data = {
|
|
Value => $Value,
|
|
Title => $Title,
|
|
Link => $Link,
|
|
};
|
|
|
|
return $Data;
|
|
}
|
|
|
|
sub SearchFieldParameterBuild {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# get field value
|
|
my $Value = $Self->SearchFieldValueGet(%Param);
|
|
|
|
my $DisplayValue;
|
|
|
|
if ( defined $Value && !$Value ) {
|
|
$DisplayValue = '';
|
|
}
|
|
|
|
if ($Value) {
|
|
if ( ref $Value eq 'ARRAY' ) {
|
|
|
|
my @DisplayItemList;
|
|
for my $Item ( @{$Value} ) {
|
|
|
|
# set the display value
|
|
my $DisplayItem = $Param{DynamicFieldConfig}->{Config}->{PossibleValues}->{$Item}
|
|
|| $Item;
|
|
|
|
# translate the value
|
|
if (
|
|
$Param{DynamicFieldConfig}->{Config}->{TranslatableValues}
|
|
&& defined $Param{LayoutObject}
|
|
)
|
|
{
|
|
$DisplayItem = $Param{LayoutObject}->{LanguageObject}->Translate($DisplayItem);
|
|
}
|
|
|
|
push @DisplayItemList, $DisplayItem;
|
|
}
|
|
|
|
# combine different values into one string
|
|
$DisplayValue = join ' + ', @DisplayItemList;
|
|
}
|
|
else {
|
|
|
|
# set the display value
|
|
$DisplayValue = $Param{DynamicFieldConfig}->{Config}->{PossibleValues}->{$Value};
|
|
|
|
# translate the value
|
|
if (
|
|
$Param{DynamicFieldConfig}->{Config}->{TranslatableValues}
|
|
&& defined $Param{LayoutObject}
|
|
)
|
|
{
|
|
$DisplayValue = $Param{LayoutObject}->{LanguageObject}->Translate($DisplayValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
# return search parameter structure
|
|
return {
|
|
Parameter => {
|
|
Equals => $Value,
|
|
},
|
|
Display => $DisplayValue,
|
|
};
|
|
}
|
|
|
|
sub StatsFieldParameterBuild {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# set PossibleValues
|
|
my $Values = $Param{DynamicFieldConfig}->{Config}->{PossibleValues};
|
|
|
|
# get historical values from database
|
|
my $HistoricalValues = $Kernel::OM->Get('Kernel::System::DynamicFieldValue')->HistoricalValueGet(
|
|
FieldID => $Param{DynamicFieldConfig}->{ID},
|
|
ValueType => 'Text,',
|
|
);
|
|
|
|
# add historic values to current values (if they don't exist anymore)
|
|
for my $Key ( sort keys %{$HistoricalValues} ) {
|
|
if ( !$Values->{$Key} ) {
|
|
$Values->{$Key} = $HistoricalValues->{$Key};
|
|
}
|
|
}
|
|
|
|
# use PossibleValuesFilter if defined
|
|
$Values = $Param{PossibleValuesFilter} // $Values;
|
|
|
|
return {
|
|
Values => $Values,
|
|
Name => $Param{DynamicFieldConfig}->{Label},
|
|
Element => 'DynamicField_' . $Param{DynamicFieldConfig}->{Name},
|
|
TranslatableValues => $Param{DynamicFieldConfig}->{Config}->{TranslatableValues},
|
|
Block => 'MultiSelectField',
|
|
};
|
|
}
|
|
|
|
sub ReadableValueRender {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# set Value and Title variables
|
|
my $Value = '';
|
|
my $Title = '';
|
|
|
|
# check value
|
|
my @Values;
|
|
if ( ref $Param{Value} eq 'ARRAY' ) {
|
|
@Values = @{ $Param{Value} };
|
|
}
|
|
else {
|
|
@Values = ( $Param{Value} );
|
|
}
|
|
|
|
my @ReadableValues;
|
|
|
|
VALUEITEM:
|
|
for my $Item (@Values) {
|
|
next VALUEITEM if !$Item;
|
|
|
|
push @ReadableValues, $Item;
|
|
}
|
|
|
|
# set new line separator
|
|
my $ItemSeparator = ', ';
|
|
|
|
# Output transformations
|
|
$Value = join( $ItemSeparator, @ReadableValues );
|
|
$Title = $Value;
|
|
|
|
# cut strings if needed
|
|
if ( $Param{ValueMaxChars} && length($Value) > $Param{ValueMaxChars} ) {
|
|
$Value = substr( $Value, 0, $Param{ValueMaxChars} ) . '...';
|
|
}
|
|
if ( $Param{TitleMaxChars} && length($Title) > $Param{TitleMaxChars} ) {
|
|
$Title = substr( $Title, 0, $Param{TitleMaxChars} ) . '...';
|
|
}
|
|
|
|
# create return structure
|
|
my $Data = {
|
|
Value => $Value,
|
|
Title => $Title,
|
|
};
|
|
|
|
return $Data;
|
|
}
|
|
|
|
sub TemplateValueTypeGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
|
|
|
|
# set the field types
|
|
my $EditValueType = 'ARRAY';
|
|
my $SearchValueType = 'ARRAY';
|
|
|
|
# return the correct structure
|
|
if ( $Param{FieldType} eq 'Edit' ) {
|
|
return {
|
|
$FieldName => $EditValueType,
|
|
};
|
|
}
|
|
elsif ( $Param{FieldType} eq 'Search' ) {
|
|
return {
|
|
'Search_' . $FieldName => $SearchValueType,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
$FieldName => $EditValueType,
|
|
'Search_' . $FieldName => $SearchValueType,
|
|
};
|
|
}
|
|
}
|
|
|
|
sub ObjectMatch {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
|
|
|
|
# the attribute must be an array
|
|
return 0 if !IsArrayRefWithData( $Param{ObjectAttributes}->{$FieldName} );
|
|
|
|
my $Match;
|
|
|
|
# search in all values for this attribute
|
|
VALUE:
|
|
for my $AttributeValue ( @{ $Param{ObjectAttributes}->{$FieldName} } ) {
|
|
|
|
next VALUE if !defined $AttributeValue;
|
|
|
|
# only need to match one
|
|
if ( $Param{Value} eq $AttributeValue ) {
|
|
$Match = 1;
|
|
last VALUE;
|
|
}
|
|
}
|
|
|
|
return $Match;
|
|
}
|
|
|
|
sub HistoricalValuesGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# get historical values from database
|
|
my $HistoricalValues = $Kernel::OM->Get('Kernel::System::DynamicFieldValue')->HistoricalValueGet(
|
|
FieldID => $Param{DynamicFieldConfig}->{ID},
|
|
ValueType => 'Text',
|
|
);
|
|
|
|
# return the historical values from database
|
|
return $HistoricalValues;
|
|
}
|
|
|
|
sub ValueLookup {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my @Keys;
|
|
if ( ref $Param{Key} eq 'ARRAY' ) {
|
|
@Keys = @{ $Param{Key} };
|
|
}
|
|
else {
|
|
@Keys = ( $Param{Key} );
|
|
}
|
|
|
|
# get real values
|
|
my $PossibleValues = $Param{DynamicFieldConfig}->{Config}->{PossibleValues};
|
|
|
|
# to store final values
|
|
my @Values;
|
|
|
|
KEYITEM:
|
|
for my $Item (@Keys) {
|
|
next KEYITEM if !$Item;
|
|
|
|
# set the value as the key by default
|
|
my $Value = $Item;
|
|
|
|
# try to convert key to real value
|
|
if ( $PossibleValues->{$Item} ) {
|
|
$Value = $PossibleValues->{$Item};
|
|
|
|
# check if translation is possible
|
|
if (
|
|
defined $Param{LanguageObject}
|
|
&& $Param{DynamicFieldConfig}->{Config}->{TranslatableValues}
|
|
)
|
|
{
|
|
|
|
# translate value
|
|
$Value = $Param{LanguageObject}->Translate($Value);
|
|
}
|
|
}
|
|
push @Values, $Value;
|
|
}
|
|
|
|
return \@Values;
|
|
}
|
|
|
|
sub BuildSelectionDataGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $FieldConfig = $Param{DynamicFieldConfig}->{Config};
|
|
my $FilteredPossibleValues = $Param{PossibleValues};
|
|
|
|
# get the possible values again as it might or might not contain the possible none and it could
|
|
# also be overwritten
|
|
my $ConfigPossibleValues = $Self->PossibleValuesGet(%Param);
|
|
|
|
# check if $PossibleValues differs from configured PossibleValues
|
|
# and show values which are not contained as disabled if TreeView => 1
|
|
if ( $FieldConfig->{TreeView} ) {
|
|
|
|
if ( keys %{$ConfigPossibleValues} != keys %{$FilteredPossibleValues} ) {
|
|
|
|
# define variables to use later in the for loop
|
|
my @Values;
|
|
my $Parents;
|
|
my %DisabledElements;
|
|
my %ProcessedElements;
|
|
my $PosibleNoneSet;
|
|
|
|
my %Values;
|
|
if ( defined $Param{Value} && IsArrayRefWithData( $Param{Value} ) ) {
|
|
|
|
# create a lookup table
|
|
%Values = map { $_ => 1 } @{ $Param{Value} };
|
|
}
|
|
|
|
# loop on all filtered possible values
|
|
for my $Key ( sort keys %{$FilteredPossibleValues} ) {
|
|
|
|
# special case for possible none
|
|
if ( !$Key && !$PosibleNoneSet && $FieldConfig->{PossibleNone} ) {
|
|
|
|
my $Selected;
|
|
if (
|
|
!IsHashRefWithData( \%Values )
|
|
|| ( defined $Values{''} && $Values{''} )
|
|
)
|
|
{
|
|
$Selected = 1;
|
|
}
|
|
|
|
# add possible none
|
|
push @Values, {
|
|
Key => $Key,
|
|
Value => $ConfigPossibleValues->{$Key} || '-',
|
|
Selected => $Selected,
|
|
};
|
|
}
|
|
|
|
# try to split its parents GrandParent::Parent::Son
|
|
my @Elements = split /::/, $Key;
|
|
|
|
# reset parents
|
|
$Parents = '';
|
|
|
|
# get each element in the hierarchy
|
|
ELEMENT:
|
|
for my $Element (@Elements) {
|
|
|
|
# add its own parents for the complete name
|
|
my $ElementLongName = $Parents . $Element;
|
|
|
|
# set new parent (before skip already processed)
|
|
$Parents .= $Element . '::';
|
|
|
|
# skip if already processed
|
|
next ELEMENT if $ProcessedElements{$ElementLongName};
|
|
|
|
my $Disabled;
|
|
|
|
# check if element exists in the original data or if it is already marked
|
|
if (
|
|
!defined $FilteredPossibleValues->{$ElementLongName}
|
|
&& !$DisabledElements{$ElementLongName}
|
|
)
|
|
{
|
|
|
|
# mark element as disabled
|
|
$DisabledElements{$ElementLongName} = 1;
|
|
|
|
# also set the disabled flag for current element to add
|
|
$Disabled = 1;
|
|
}
|
|
|
|
# set element as already processed
|
|
$ProcessedElements{$ElementLongName} = 1;
|
|
|
|
# check if the current element is the selected one
|
|
my $Selected;
|
|
if ( IsHashRefWithData( \%Values ) && $Values{$ElementLongName} ) {
|
|
$Selected = 1;
|
|
}
|
|
|
|
# add element to the new list of possible values (now including missing parents)
|
|
push @Values, {
|
|
Key => $ElementLongName,
|
|
Value => $ConfigPossibleValues->{$ElementLongName} || $ElementLongName,
|
|
Disabled => $Disabled,
|
|
Selected => $Selected,
|
|
};
|
|
}
|
|
}
|
|
$FilteredPossibleValues = \@Values;
|
|
}
|
|
}
|
|
|
|
return $FilteredPossibleValues;
|
|
}
|
|
|
|
1;
|
|
|
|
=head1 TERMS AND CONDITIONS
|
|
|
|
This software is part of the OTRS project (L<https://otrs.org/>).
|
|
|
|
This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
the enclosed file COPYING for license information (GPL). If you
|
|
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
|
|
|
=cut
|