# -- # 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::SysConfig::Base::Framework; use strict; use warnings; use Kernel::System::VariableCheck qw(:all); our @ObjectDependencies = ( 'Kernel::System::Log', 'Kernel::System::Main', 'Kernel::System::Storable', ); =head1 NAME Kernel::System::SysConfig::Base::Framework - Base class for system configuration. =head1 PUBLIC INTERFACE =head2 SettingModifiedXMLContentParsedGet() Returns perl structure for modified setting. my $Result = $SysConfigObject->SettingModifiedXMLContentParsedGet( ModifiedSetting => { EffectiveValue => 'Scalar value updated' }, DefaultSetting => { XMLContentParsed => { Value => [ { 'Item' => [ { 'Content' => "Scalar value", }, ], }, ], }, }, ); Returns: $Result = [ { 'Item' => [ { 'Content' => "Scalar value updated", }, ], }, ]; =cut sub SettingModifiedXMLContentParsedGet { my ( $Self, %Param ) = @_; for my $Needed (qw(DefaultSetting ModifiedSetting)) { if ( !$Param{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $Needed!" ); return; } } my $Result = $Param{DefaultSetting}->{XMLContentParsed}; $Result = $Self->_ModifiedValueCalculate( Value => $Result->{Value}, EffectiveValue => $Param{ModifiedSetting}->{EffectiveValue}, ); return $Result; } =head1 PRIVATE INTERFACE =head2 _ModifiedValueCalculate() Recursive helper for SettingModifiedXMLContentParsedGet(). my $Result = $SysConfigObject->_ModifiedValueCalculate( 'EffectiveValue' => 'Scalar value updated', # (optional) new effective value 'Value' => [ # (required) the XMLContentParsed value from Defaults { 'Item' => [ { 'Content' => 'Scalar value', }, ], }, ], ); Returns: $Result = [ { 'Item' => [ { 'Content' => 'Scalar value updated' }, ], }, ]; =cut sub _ModifiedValueCalculate { my ( $Self, %Param ) = @_; for my $Needed (qw(Value)) { if ( !$Param{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $Needed!" ); return; } } my %Objects; if ( $Param{Objects} ) { %Objects = %{ $Param{Objects} }; } my @SkipParameters = ( 'Hash', 'Array', 'Item', 'Content', 'Key', ); my $Result; my $ValueType; # Check if additional parameters are provided. if ( IsHashRefWithData( $Param{Parameters} ) && $Param{Value}->[0]->{Item} ) { for my $Parameter ( sort keys %{ $Param{Parameters} } ) { $Result->[0]->{Item}->[0]->{$Parameter} = $Param{Parameters}->{$Parameter}; } } if ( $Param{Value}->[0]->{Item} && $Param{Value}->[0]->{Item}->[0]->{ValueType} ) { $ValueType = $Param{Value}->[0]->{Item}->[0]->{ValueType}; } if ( $Param{ValueType} ) { $ValueType = $Param{ValueType}; } if ($ValueType) { if ( !$Objects{$ValueType} ) { # Make sure the ValueType backed is present and is syntactically correct. my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require( "Kernel::System::SysConfig::ValueType::$ValueType", ); return $Result if !$Loaded; # Create object instance. $Objects{$ValueType} = $Kernel::OM->Get( "Kernel::System::SysConfig::ValueType::$ValueType", ); } $Result = $Objects{$ValueType}->ModifiedValueGet(%Param); # Get all additional parameters (defined as attributes in XML). if ( IsHashRefWithData( $Param{Value}->[0]->{Item}->[0] ) ) { PARAMETER: for my $Parameter ( sort keys %{ $Param{Value}->[0]->{Item}->[0] } ) { next PARAMETER if grep { $_ eq $Parameter } @SkipParameters; # Skip already defined values. next PARAMETER if $Result->[0]->{Item}->[0]->{$Parameter}; $Result->[0]->{Item}->[0]->{$Parameter} = $Param{Value}->[0]->{Item}->[0]->{$Parameter}; } } } elsif ( ref $Param{EffectiveValue} eq 'ARRAY' ) { # Create basic structure. $Result = [ { 'Array' => [ { 'Item' => [], }, ], }, ]; my $DefaultItem = $Param{Value}->[0]->{Array}->[0]->{DefaultItem}; if ( $Param{Value}->[0]->{Array}->[0]->{MinItems} ) { $Result->[0]->{Array}->[0]->{MinItems} = $Param{Value}->[0]->{Array}->[0]->{MinItems}; } if ( $Param{Value}->[0]->{Array}->[0]->{MaxItems} ) { $Result->[0]->{Array}->[0]->{MaxItems} = $Param{Value}->[0]->{Array}->[0]->{MaxItems}; } my %Attributes; if ( $DefaultItem && ref $DefaultItem eq 'ARRAY' && scalar @{$DefaultItem} && ref $DefaultItem->[0] eq 'HASH' ) { # Get additional attributes ATTRIBUTE: for my $Attribute ( sort keys %{ $DefaultItem->[0] } ) { next ATTRIBUTE if grep { $Attribute eq $_ } qw(Hash Array Item Content); $Attributes{$Attribute} = $DefaultItem->[0]->{$Attribute}; } } for my $Index ( 0 .. scalar @{ $Param{EffectiveValue} } - 1 ) { if ( $DefaultItem && $DefaultItem->[0]->{ValueType} && $Param{Value}->[0]->{Array}->[0]->{Item} ) { # It's Item with defined ValueType. my $ItemData = $Kernel::OM->Get('Kernel::System::Storable')->Clone( Data => $DefaultItem, ); my $Value = $Self->_ModifiedValueCalculate( Value => [ { Item => $ItemData, }, ], EffectiveValue => $Param{EffectiveValue}->[$Index], ValueType => $Param{Value}->[0]->{Array}->[0]->{ValueType}, Objects => \%Objects, ); push @{ $Result->[0]->{Array}->[0]->{Item} }, $Value->[0]; } elsif ( $DefaultItem && ( $DefaultItem->[0]->{Array} || $DefaultItem->[0]->{Hash} ) ) { # It's complex structure (AoA or AoH), continue recursion. my $StructureType = $DefaultItem->[0]->{Array} ? 'Array' : 'Hash'; $Param{Value}->[0]->{Array}->[0]->{Item}->[0]->{$StructureType}->[0]->{DefaultItem} = $DefaultItem->[0]->{$StructureType}->[0]->{DefaultItem}; my $Value = $Self->_ModifiedValueCalculate( Value => $Param{Value}->[0]->{Array}->[0]->{Item}, EffectiveValue => $Param{EffectiveValue}->[$Index], Objects => \%Objects, ); push @{ $Result->[0]->{Array}->[0]->{Item} }, $Value->[0]; } else { if ( IsArrayRefWithData( $Param{EffectiveValue}->[$Index] ) ) { for my $ArrayItem ( @{ $Param{EffectiveValue}->[$Index] } ) { push @{ $Result->[0]->{Array}->[0]->{Item} }, { %Attributes, Content => $ArrayItem, }; } } else { # This is a string value. push @{ $Result->[0]->{Array}->[0]->{Item} }, { %Attributes, Content => $Param{EffectiveValue}->[$Index], }; } } } } elsif ( ref $Param{EffectiveValue} eq 'HASH' ) { # Create basic structure. $Result = [ { 'Hash' => [ { 'Item' => [], }, ], } ]; if ( $Param{Value}->[0]->{Hash}->[0]->{MinItems} ) { $Result->[0]->{Hash}->[0]->{MinItems} = $Param{Value}->[0]->{Hash}->[0]->{MinItems}; } if ( $Param{Value}->[0]->{Hash}->[0]->{MaxItems} ) { $Result->[0]->{Hash}->[0]->{MaxItems} = $Param{Value}->[0]->{Hash}->[0]->{MaxItems}; } my $DefaultItem; my %Attributes; for my $Key ( sort keys %{ $Param{EffectiveValue} } ) { %Attributes = (); $DefaultItem = $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}; if ( $Param{Value}->[0]->{Hash}->[0]->{Item} ) { my @ItemWithSameKey = grep { $Key eq ( $Param{Value}->[0]->{Hash}->[0]->{Item}->[$_]->{Key} || '' ) } 0 .. scalar @{ $Param{Value}->[0]->{Hash}->[0]->{Item} } - 1; if ( scalar @ItemWithSameKey ) { if ( $DefaultItem && !$Param{Value}->[0]->{Hash}->[0]->{Item}->[ $ItemWithSameKey[0] ]->{ValueType} && $DefaultItem->[0]->{ValueType} ) { # update hash for my $DefaultKey ( sort keys %{ $Param{Value}->[0]->{Hash}->[0]->{Item}->[ $ItemWithSameKey[0] ] } ) { $DefaultItem->[0]->{$DefaultKey} = $Param{Value}->[0]->{Hash}->[0]->{Item}->[ $ItemWithSameKey[0] ]->{$DefaultKey}; } } else { $DefaultItem = [ $Param{Value}->[0]->{Hash}->[0]->{Item}->[ $ItemWithSameKey[0] ], ]; } } } if ( $DefaultItem && ref $DefaultItem eq 'ARRAY' && scalar @{$DefaultItem} && ref $DefaultItem->[0] eq 'HASH' ) { # Get additional attributes ATTRIBUTE: for my $Attribute ( sort keys %{ $DefaultItem->[0] } ) { next ATTRIBUTE if grep { $Attribute eq $_ } qw(Hash Array Content Key); if ( $Attribute eq 'Item' ) { if ( !$DefaultItem->[0]->{Item}->[0]->{ValueType} || $DefaultItem->[0]->{Item}->[0]->{ValueType} ne 'Option' ) { next ATTRIBUTE; } } $Attributes{$Attribute} = $DefaultItem->[0]->{$Attribute}; } } if ( $DefaultItem && !$DefaultItem->[0]->{Content} && $Param{Value}->[0]->{Hash}->[0]->{Item} && scalar @{ $Param{Value}->[0]->{Hash}->[0]->{Item} } && $Param{Value}->[0]->{Hash}->[0]->{Item}->[0]->{Item} ) { # It's Item with defined ValueType. my $ItemData = $Kernel::OM->Get('Kernel::System::Storable')->Clone( Data => $DefaultItem, ); ATTRIBUTE: for my $Attribute ( sort keys %Attributes ) { next ATTRIBUTE if defined $ItemData->[0]->{$Attribute}; $ItemData->[0]->{$Attribute} = $Attributes{$Attribute}; } if ( !$ItemData->[0]->{Item} || ( $ItemData->[0]->{Item} && !$ItemData->[0]->{Item}->[0]->{ValueType} ) ) { $ItemData->[0]->{ValueType} //= 'String'; } my $Value = $Self->_ModifiedValueCalculate( Value => $ItemData, EffectiveValue => $Param{EffectiveValue}->{$Key}, ValueType => $DefaultItem->[0]->{ValueType}, Objects => \%Objects, ); $Value->[0]->{Key} = $Key; push @{ $Result->[0]->{Hash}->[0]->{Item} }, $Value->[0]; } elsif ( $DefaultItem && ( $DefaultItem->[0]->{Array} || $DefaultItem->[0]->{Hash} ) ) { # It's complex structure (HoA or HoH), continue recursion. my $StructureType = $DefaultItem->[0]->{Array} ? 'Array' : 'Hash'; my ($SubValue) = grep { defined $_->{Key} && $_->{Key} eq $Key } @{ $Param{Value}->[0]->{Hash}->[0]->{Item} }; if ( $Param{Value}->[0]->{Hash}->[0]->{DefaultItem} && $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{$StructureType} ) { $SubValue->{$StructureType}->[0]->{DefaultItem} = $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{$StructureType}->[0]->{DefaultItem}; } my $Value = $Self->_ModifiedValueCalculate( Value => [$SubValue], EffectiveValue => $Param{EffectiveValue}->{$Key}, Objects => \%Objects, ); $Value->[0]->{Key} = $Key; if ( $SubValue->{$StructureType}->[0]->{DefaultItem} ) { $Value->[0]->{$StructureType}->[0]->{DefaultItem} = $SubValue->{$StructureType}->[0]->{DefaultItem}; } push @{ $Result->[0]->{Hash}->[0]->{Item} }, $Value->[0]; } else { # This is a scaler value. my $ValueAttribute = "Content"; # by default my $ValueType = $Attributes{ValueType}; if ($ValueType) { if ( !$Objects{$ValueType} ) { # Make sure the ValueType backed is present and is syntactically correct. my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require( "Kernel::System::SysConfig::ValueType::$ValueType", ); if ($Loaded) { # Create object instance. $Objects{$ValueType} = $Kernel::OM->Get( "Kernel::System::SysConfig::ValueType::$ValueType", ); } } $ValueAttribute = $Objects{$ValueType}->ValueAttributeGet(); } push @{ $Result->[0]->{Hash}->[0]->{Item} }, { %Attributes, Key => $Key, $ValueAttribute => $Param{EffectiveValue}->{$Key}, }; } } } else { # This is a scaler value. $Result = [ { Item => [ { Content => $Param{EffectiveValue}, }, ], }, ]; # Get all additional parameters (defined as attributes in XML). if ( IsHashRefWithData( $Param{Value}->[0]->{Item}->[0] ) ) { PARAMETER: for my $Parameter ( sort keys %{ $Param{Value}->[0]->{Item}->[0] } ) { next PARAMETER if grep { $_ eq $Parameter } @SkipParameters; $Result->[0]->{Item}->[0]->{$Parameter} = $Param{Value}->[0]->{Item}->[0]->{$Parameter}; } } } return $Result; } 1; =head1 TERMS AND CONDITIONS This software is part of the OTRS project (L). 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. =cut