1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8 9package Kernel::System::SysConfig::ValueType::Select; 10## nofilter(TidyAll::Plugin::OTRS::Perl::LayoutObject) 11 12use strict; 13use warnings; 14 15use Kernel::System::VariableCheck qw(:all); 16 17use parent qw(Kernel::System::SysConfig::BaseValueType); 18 19our @ObjectDependencies = ( 20 'Kernel::Language', 21 'Kernel::Output::HTML::Layout', 22 'Kernel::System::Log', 23); 24 25=head1 NAME 26 27Kernel::System::SysConfig::ValueType::Select - System configuration select value type backed. 28 29=head1 PUBLIC INTERFACE 30 31=head2 new() 32 33Create an object. Do not use it directly, instead use: 34 35 use Kernel::System::ObjectManager; 36 local $Kernel::OM = Kernel::System::ObjectManager->new(); 37 my $ValueTypeObject = $Kernel::OM->Get('Kernel::System::SysConfig::ValueType::Select'); 38 39=cut 40 41sub new { 42 my ( $Type, %Param ) = @_; 43 44 # Allocate new hash for object. 45 my $Self = {}; 46 bless( $Self, $Type ); 47 48 return $Self; 49} 50 51=head2 SettingEffectiveValueCheck() 52 53Check if provided EffectiveValue matches structure defined in XMLContentParsed. 54 55 my %Result = $ValueTypeObject->SettingEffectiveValueCheck( 56 XMLContentParsed => { 57 Value => [ 58 { 59 'Item' => [ 60 { 61 'Item' => [ 62 { 63 'Content' => 'Option 1', 64 'Value' => 'option-1', 65 'ValueType' => 'Option', 66 }, 67 { 68 'Content' => 'Option 2', 69 'Value' => 'option-2', 70 'ValueType' => 'Option', 71 }, 72 ], 73 'SelectedID' => 'option-1', 74 'ValueType' => 'Select', 75 }, 76 ], 77 }, 78 ], 79 }, 80 EffectiveValue => 'option-1', 81 ); 82 83Result: 84 %Result = ( 85 EffectiveValue => 'option-1', # Note for Select ValueTypes EffectiveValue is not changed. 86 Success => 1, 87 Error => undef, 88 ); 89 90=cut 91 92sub SettingEffectiveValueCheck { 93 my ( $Self, %Param ) = @_; 94 95 for my $Needed (qw(XMLContentParsed)) { 96 if ( !$Param{$Needed} ) { 97 $Kernel::OM->Get('Kernel::System::Log')->Log( 98 Priority => 'error', 99 Message => "Need $Needed!" 100 ); 101 102 return; 103 } 104 } 105 106 my %Result = ( 107 Success => 0, 108 ); 109 110 my $Value = $Param{XMLContentParsed}->{Value}; 111 112 for my $Parameter ( sort keys %{ $Param{Parameters} } ) { 113 if ( !defined $Value->[0]->{Item}->[0]->{$Parameter} ) { 114 $Value->[0]->{Item}->[0]->{$Parameter} = $Param{Parameters}->{$Parameter}; 115 } 116 } 117 118 # Data should be scalar. 119 if ( ref $Param{EffectiveValue} ) { 120 $Result{Error} = 'EffectiveValue for Select must be a scalar!'; 121 return %Result; 122 } 123 124 if ( 125 !grep { 126 $Param{EffectiveValue} eq $_->{Value} 127 || ( !$Param{EffectiveValue} && !$_->{Value} ) 128 } 129 @{ $Value->[0]->{Item}->[0]->{Item} } 130 ) 131 { 132 $Result{Error} = "'$Param{EffectiveValue}' option not found in Select!"; 133 return %Result; 134 } 135 136 $Result{Success} = 1; 137 $Result{EffectiveValue} = $Param{EffectiveValue}; 138 139 return %Result; 140} 141 142sub EffectiveValueGet { 143 my ( $Self, %Param ) = @_; 144 145 if ( !IsArrayRefWithData( $Param{Value} ) ) { 146 $Kernel::OM->Get('Kernel::System::Log')->Log( 147 Priority => 'error', 148 Message => "Value is missing or invalid!", 149 ); 150 151 return ''; 152 } 153 154 if ( scalar @{ $Param{Value} } > 1 ) { 155 $Kernel::OM->Get('Kernel::System::Log')->Log( 156 Priority => 'error', 157 Message => "Value must be a single element!", 158 ); 159 return ''; 160 } 161 162 $Param{Value}->[0]->{SelectedID} //= ''; 163 164 # Check if option is translatable. 165 my ($Option) = grep { $_->{Value} eq $Param{Value}->[0]->{SelectedID} } 166 @{ $Param{Value}->[0]->{Item} }; 167 168 if ( !defined $Option ) { 169 170 # TODO: Should this really be logged? 171 $Kernel::OM->Get('Kernel::System::Log')->Log( 172 Priority => 'error', 173 Message => "'$Param{Value}->[0]->{SelectedID}' not found in select!", 174 ); 175 } 176 177 my $EffectiveValue = $Param{Value}->[0]->{SelectedID}; 178 179 if ( 180 $Param{Translate} 181 && 182 $Option && 183 $Option->{Translatable} 184 ) 185 { 186 $EffectiveValue = $Kernel::OM->Get('Kernel::Language')->Translate($EffectiveValue); 187 } 188 189 return $EffectiveValue; 190} 191 192sub ModifiedValueGet { 193 my ( $Self, %Param ) = @_; 194 195 for my $Needed (qw(Value)) { 196 if ( !$Param{$Needed} ) { 197 $Kernel::OM->Get('Kernel::System::Log')->Log( 198 Priority => 'error', 199 Message => "Need $Needed!", 200 ); 201 return; 202 } 203 } 204 205 my $Result = $Param{Value}; 206 207 # Update Content 208 $Result->[0]->{Item}->[0]->{SelectedID} = $Param{EffectiveValue} || ''; 209 210 return $Result; 211} 212 213=head2 SettingRender() 214 215Extracts the effective value from a XML parsed setting. 216 217 my $SettingHTML = $ValueTypeObject->SettingRender( 218 Name => 'SettingName', 219 DefaultID => 123, # (required) 220 EffectiveValue => '3 medium', 221 DefaultValue => '3 medium', # (optional) 222 Class => 'My class' # (optional) 223 RW => 1, # (optional) Allow editing. Default 0. 224 Item => [ # (optional) XML parsed item 225 { 226 'ValueType' => 'Select', 227 ... 228 }, 229 ], 230 IsArray => 1, # (optional) Item is part of the array 231 IsHash => 1, # (optional) Item is part of the hash 232 Key => 'Key', # (optional) Hash key (if available) 233 SkipEffectiveValueCheck => 1, # (optional) If enabled, system will not perform effective value check. 234 # Default: 1. 235 ); 236 237Returns: 238 239 $SettingHTML = '<div class "Field"...</div>'; 240 241=cut 242 243sub SettingRender { 244 my ( $Self, %Param ) = @_; 245 246 for my $Needed (qw(Name EffectiveValue Item)) { 247 if ( !defined $Param{$Needed} ) { 248 $Kernel::OM->Get('Kernel::System::Log')->Log( 249 Priority => 'error', 250 Message => "Need $Needed", 251 ); 252 return; 253 } 254 } 255 256 $Param{Class} //= ''; 257 $Param{DefaultValue} //= ''; 258 $Param{IDSuffix} //= ''; 259 260 if ( !IsArrayRefWithData( $Param{Item} ) ) { 261 $Kernel::OM->Get('Kernel::System::Log')->Log( 262 Priority => 'error', 263 Message => "Item is invalid!", 264 ); 265 } 266 267 my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); 268 269 my $EffectiveValue = $Param{EffectiveValue}; 270 271 my %EffectiveValueCheck = ( 272 Success => 1, 273 ); 274 275 if ( !$Param{SkipEffectiveValueCheck} ) { 276 %EffectiveValueCheck = $Self->SettingEffectiveValueCheck( 277 EffectiveValue => $EffectiveValue, 278 XMLContentParsed => { 279 Value => [ 280 { 281 Item => $Param{Item}, 282 }, 283 ], 284 }, 285 ); 286 } 287 288 my %Data; 289 OPTION: 290 for my $Option ( @{ $Param{Item}->[0]->{Item} } ) { 291 next OPTION if $Option->{ValueType} ne 'Option'; 292 293 if ( $Option->{Translatable} ) { 294 295 $Data{ $Option->{Value} } = $LanguageObject->Translate( $Option->{Content} ); 296 next OPTION; 297 } 298 $Data{ $Option->{Value} } = $Option->{Content}; 299 } 300 301 # find data in hash if provided 302 if ( !%Data && $Param{Value}->[0]->{Hash}->[0]->{Item} ) { 303 my ($OptionItems) = grep { $_->{Key} eq $Param{Key} } @{ $Param{Value}->[0]->{Hash}->[0]->{Item} }; 304 305 OPTION: 306 for my $Option ( @{ $OptionItems->{Item} } ) { 307 next OPTION if $Option->{ValueType} ne 'Option'; 308 309 if ( $Option->{Translatable} ) { 310 $Data{ $Option->{Value} } = $LanguageObject->Translate( $Option->{Content} ); 311 next OPTION; 312 } 313 $Data{ $Option->{Value} } = $Option->{Content}; 314 } 315 } 316 317 # data not found, try in DefaultItem 318 if ( 319 !%Data 320 && $Param{Value}->[0]->{Hash}->[0]->{DefaultItem} 321 && $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{Item} 322 ) 323 { 324 OPTION: 325 for my $Option ( @{ $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{Item} } ) { 326 next OPTION if $Option->{ValueType} ne 'Option'; 327 328 if ( $Option->{Translatable} ) { 329 $Data{ $Option->{Value} } = $LanguageObject->Translate( $Option->{Content} ); 330 next OPTION; 331 } 332 $Data{ $Option->{Value} } = $Option->{Content}; 333 } 334 } 335 336 # When displaying diff between current and old value, it can happen that value is missing 337 # since it was renamed, or removed. In this case, we need to add this "old" value also. 338 if ( 339 !grep { 340 $_ eq $EffectiveValue 341 || ( !$EffectiveValue && !$_ ) 342 } keys %Data 343 ) 344 { 345 $Data{$EffectiveValue} = $EffectiveValue; 346 } 347 348 my $OptionStrg = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->BuildSelection( 349 Name => $Param{Name}, 350 ID => $Param{Name} . $Param{IDSuffix}, 351 Disabled => $Param{RW} ? 0 : 1, 352 Data => \%Data, 353 SelectedID => $EffectiveValue, 354 Class => "$Param{Class} Modernize", 355 Translation => 0, 356 ); 357 358 my $HTML = "<div class='SettingContent'>\n"; 359 $HTML .= $OptionStrg; 360 361 if ( !$EffectiveValueCheck{Success} ) { 362 my $Message = $LanguageObject->Translate("Value is not correct! Please, consider updating this field."); 363 364 $HTML .= $Param{IsValid} ? "<div class='BadEffectiveValue'>\n" : "<div>\n"; 365 $HTML .= "<p>* $Message</p>\n"; 366 $HTML .= "</div>\n"; 367 } 368 369 $HTML .= "</div>\n"; 370 371 if ( !$Param{IsArray} && !$Param{IsHash} && defined $Param{DefaultValue} ) { 372 my $DefaultValueStrg = $LanguageObject->Translate('Default'); 373 374 $HTML .= <<"EOF"; 375 376 <div class=\"WidgetMessage Bottom\"> 377 $DefaultValueStrg: $Param{DefaultValue} 378 </div> 379EOF 380 } 381 return $HTML; 382} 383 384=head2 AddItem() 385 386Generate HTML for new array/hash item. 387 388 my $HTML = $ValueTypeObject->AddItem( 389 Name => 'SettingName', (required) Name 390 DefaultItem => { (required) DefaultItem hash 391 'ValueType' => 'Select', 392 'Content' => 'optiont-1', 393 }, 394 IDSuffix => '_Array1', (optional) IDSuffix is needed for arrays and hashes. 395 ); 396 397Returns: 398 399 $HTML = '<select class="Modernize" id="SettingName" name="SettingName" title="SettingName"> 400 ... 401 </select>'; 402 403=cut 404 405sub AddItem { 406 my ( $Self, %Param ) = @_; 407 408 # Check needed stuff. 409 for my $Needed (qw(Name DefaultItem)) { 410 if ( !$Param{$Needed} ) { 411 $Kernel::OM->Get('Kernel::System::Log')->Log( 412 Priority => 'error', 413 Message => "Need $Needed!", 414 ); 415 return; 416 } 417 } 418 419 $Param{Class} //= ''; 420 $Param{DefaultValue} //= ''; 421 $Param{IDSuffix} //= ''; 422 423 my %Data; 424 425 my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); 426 427 OPTION: 428 for my $Option ( @{ $Param{DefaultItem}->{Item} } ) { 429 next OPTION if $Option->{ValueType} ne 'Option'; 430 431 if ( $Option->{Translatable} ) { 432 $Data{ $Option->{Value} } = $LanguageObject->Translate( $Option->{Content} ); 433 next OPTION; 434 } 435 $Data{ $Option->{Value} } = $Option->{Content}; 436 } 437 438 my $Result = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->BuildSelection( 439 Name => $Param{Name}, 440 ID => $Param{Name} . $Param{IDSuffix}, 441 Data => \%Data, 442 SelectedID => $Param{DefaultItem}->{SelectedID} || '', 443 Class => "$Param{Class} Modernize Entry", 444 Title => $Param{Name}, 445 Translation => 0, 446 ); 447 448 return $Result; 449} 450 451=head2 ValueAttributeGet() 452 453Returns attribute name in the parsed XML that contains Value. 454 455 my $Result = $ValueTypeObject->ValueAttributeGet(); 456Result: 457 $Result = 'SelectedID'; 458 459=cut 460 461sub ValueAttributeGet { 462 my ( $Self, %Param ) = @_; 463 464 return 'SelectedID'; 465} 466 467=head2 ForbiddenValueTypes() 468 469Return array of value types that are not allowed inside this value type. 470 471 my @ForbiddenValueTypes = $ValueTypeObject->ForbiddenValueTypes(); 472 473Returns: 474 475 @ForbiddenValueTypes = ( 476 'Option', 477 ... 478 ); 479 480=cut 481 482sub ForbiddenValueTypes { 483 my ( $Self, %Param ) = @_; 484 485 return ("Option"); 486} 487 4881; 489 490=head1 TERMS AND CONDITIONS 491 492This software is part of the OTRS project (L<https://otrs.org/>). 493 494This software comes with ABSOLUTELY NO WARRANTY. For details, see 495the enclosed file COPYING for license information (GPL). If you 496did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 497 498=cut 499