# --
# 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::ImportExport::FormatBackend::CSV;
use strict;
use warnings;
use Kernel::Language qw(Translatable);
our @ObjectDependencies = (
'Kernel::System::ImportExport',
'Kernel::System::Log',
'Kernel::System::Main',
);
=head1 NAME
Kernel::System::ImportExport::FormatBackend::CSV - import/export backend for CSV
=head1 DESCRIPTION
All functions to import and export a csv format
=cut
=head2 new()
Create an object
use Kernel::System::ObjectManager;
local $Kernel::OM = Kernel::System::ObjectManager->new();
my $ImportExportCSVBackendObject = $Kernel::OM->Get('Kernel::System::ImportExport::FormatBackend::CSV');
=cut
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {};
bless( $Self, $Type );
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require('Text::CSV') ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "CPAN module Text::CSV is required to use the CSV import/export module!",
);
return;
}
# define available separators
$Self->{AvailableSeparators} = {
Tabulator => "\t",
Semicolon => ';',
Colon => ':',
Dot => '.',
Comma => ',',
};
return $Self;
}
=head2 FormatAttributesGet()
Get the format attributes of a format as array/hash reference
my $Attributes = $FormatBackend->FormatAttributesGet(
UserID => 1,
);
=cut
sub FormatAttributesGet {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserID!',
);
return;
}
my $Attributes = [
{
Key => 'ColumnSeparator',
Name => Translatable('Column Separator'),
Input => {
Type => 'Selection',
Data => {
Tabulator => Translatable('Tabulator (TAB)'),
Semicolon => Translatable('Semicolon (;)'),
Colon => Translatable('Colon (:)'),
Dot => Translatable('Dot (.)'),
Comma => Translatable('Comma (,)'),
},
Required => 1,
Translation => 1,
PossibleNone => 1,
},
},
{
Key => 'Charset',
Name => Translatable('Charset'),
Input => {
Type => 'Text',
ValueDefault => 'UTF-8',
Required => 1,
Translation => 0,
Size => 20,
MaxLength => 20,
Readonly => 1,
},
},
{
Key => 'IncludeColumnHeaders',
Name => Translatable('Include Column Headers'),
Input => {
Type => 'Selection',
Data => {
0 => Translatable('No'),
1 => Translatable('Yes'),
},
Translation => 1,
PossibleNone => 0,
},
},
];
return $Attributes;
}
=head2 MappingFormatAttributesGet()
Get the mapping attributes of an format as array/hash reference
my $Attributes = $FormatBackend->MappingFormatAttributesGet(
UserID => 1,
);
=cut
sub MappingFormatAttributesGet {
my ( $Self, %Param ) = @_;
# check needed object
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserID!',
);
return;
}
my $Attributes = [
{
Key => 'Column',
Name => Translatable('Column'),
Input => {
Type => 'TT',
Data => '',
Required => 0,
},
},
];
return $Attributes;
}
=head2 ImportDataGet()
Get import data as C<2D-array> reference
my $ImportData = $FormatBackend->ImportDataGet(
TemplateID => 123,
SourceContent => $StringRef, # (optional)
UserID => 1,
);
=cut
sub ImportDataGet {
my ( $Self, %Param ) = @_;
# check needed stuff
for my $Argument (qw(TemplateID UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
return [] if !defined $Param{SourceContent};
# check source content
if ( ref $Param{SourceContent} ne 'SCALAR' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'SourceContent must be a scalar reference',
);
return;
}
# get format data
my $FormatData = $Kernel::OM->Get('Kernel::System::ImportExport')->FormatDataGet(
TemplateID => $Param{TemplateID},
UserID => $Param{UserID},
);
# check format data
if ( !$FormatData || ref $FormatData ne 'HASH' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No format data found for the template id $Param{TemplateID}",
);
return;
}
# get charset
my $Charset = $FormatData->{Charset} ||= '';
# check the charset
if ( $Charset ne 'UTF-8' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No valid charset found for the template id $Param{TemplateID}. Charset must be UTF-8!",
);
return;
}
# get separator
$FormatData->{ColumnSeparator} ||= '';
my $Separator = $Self->{AvailableSeparators}->{ $FormatData->{ColumnSeparator} } || '';
# check the separator
if ( !$Separator ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No valid separator found for the template id $Param{TemplateID}",
);
return;
}
# create the parser object
my $ParseObject = Text::CSV->new(
{
quote_char => '"',
escape_char => '"',
sep_char => $Separator,
eol => '',
always_quote => 1,
binary => 1,
keep_meta_info => 0,
allow_loose_quotes => 0,
allow_loose_escapes => 0,
allow_whitespace => 0,
blank_is_undef => 0,
verbatim => 0,
}
);
# create an in memory temp file and open it
my $FileContent = '';
open my $FH, '+<', \$FileContent; ## no critic
# write source content
print $FH ${ $Param{SourceContent} };
# rewind file handle
seek $FH, 0, 0;
# parse the content
my $LineCount = 1;
my @ImportData;
# it is important to use this syntax "while ( !eof($FH) )"
# as the CPAN module Text::CSV_XS might show errors if the
# getline call is within the while test
# have a look at http://bugs.otrs.org/show_bug.cgi?id=9270
while ( !eof($FH) ) {
my $Column = $ParseObject->getline($FH);
push @ImportData, $Column;
$LineCount++;
}
# error handling
my ( $ParseErrorCode, $ParseErrorString ) = $ParseObject->error_diag();
if ($ParseErrorCode) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "ImportError at line $LineCount, "
. "ErrorCode: $ParseErrorCode '$ParseErrorString' ",
);
}
# close the in memory file handle
close $FH;
# set utf8 flag
for my $Row (@ImportData) {
for my $Cell ( @{$Row} ) {
Encode::_utf8_on($Cell);
}
}
return \@ImportData;
}
=head2 ExportDataSave()
Export one row of the export data
my $DestinationContent = $FormatBackend->ExportDataSave(
TemplateID => 123,
ExportDataRow => $ArrayRef,
UserID => 1,
);
=cut
sub ExportDataSave {
my ( $Self, %Param ) = @_;
# check needed stuff
for my $Argument (qw(TemplateID ExportDataRow UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# check export data row
if ( ref $Param{ExportDataRow} ne 'ARRAY' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'ExportDataRow must be an array reference',
);
return;
}
# get format data
my $FormatData = $Kernel::OM->Get('Kernel::System::ImportExport')->FormatDataGet(
TemplateID => $Param{TemplateID},
UserID => $Param{UserID},
);
# check format data
if ( !$FormatData || ref $FormatData ne 'HASH' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No format data found for the template id $Param{TemplateID}",
);
return;
}
# get charset
my $Charset = $FormatData->{Charset} ||= '';
# check the charset
if ( $Charset ne 'UTF-8' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No valid charset found for the template id $Param{TemplateID}. Charset must be UTF-8!",
);
return;
}
# get columnn separator
$FormatData->{ColumnSeparator} ||= '';
my $Separator = $Self->{AvailableSeparators}->{ $FormatData->{ColumnSeparator} } || '';
# check the separator
if ( !$Separator ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No valid separator found for the template id $Param{TemplateID}",
);
return;
}
# create the parser object
my $ParseObject = Text::CSV->new(
{
quote_char => '"',
escape_char => '"',
sep_char => $Separator,
eol => '',
always_quote => 1,
binary => 1,
keep_meta_info => 0,
allow_loose_quotes => 0,
allow_loose_escapes => 0,
allow_whitespace => 0,
blank_is_undef => 0,
verbatim => 0,
}
);
if ( !$ParseObject->combine( @{ $Param{ExportDataRow} } ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Can't combine the export data to a string!",
);
return;
}
# create the CSV string
my $String = $ParseObject->string();
# set utf8 flag
Encode::_utf8_on($String);
return $String;
}
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