Csv Import Helper: classenlose profile dürfen den Dispatcher nicht abschiessen.
[kivitendo-erp.git] / SL / Helper / Csv / Dispatcher.pm
index 31c5eba..be3fadd 100644 (file)
@@ -9,6 +9,8 @@ use Rose::Object::MakeMethods::Generic scalar => [ qw(
   _specs _errors
 ) ];
 
+use SL::Helper::Csv::Error;
+
 sub new {
   my ($class, $parent) = @_;
   my $self = bless { }, $class;
@@ -36,7 +38,6 @@ sub apply {
     if ($class) {
 
       # autovifify
-      eval "require $class; 1" or die "could not load class '$class'";
       if (defined $index) {
         if (! $obj->$acc || !$obj->$acc->[$index]) {
           my @objects = $obj->$acc;
@@ -70,7 +71,15 @@ sub parse_profile {
 
   for my $col (@$header) {
     next unless $col;
-    push @specs, $self->make_spec($col, $profile->{$col} || $col);
+    if ($self->_csv->strict_profile) {
+      if (exists $profile->{$col}) {
+        push @specs, $self->make_spec($col, $profile->{$col});
+      } else {
+        $self->unknown_column($col, undef);
+      }
+    } else {
+      push @specs, $self->make_spec($col, $profile->{$col} || $col);
+    }
   }
 
   $self->_specs(\@specs);
@@ -84,13 +93,27 @@ sub make_spec {
   my $spec = { key => $col, steps => [] };
   my $cur_class = $self->_csv->class;
 
+  return unless $cur_class;
+
   for my $step_index ( split /\.(?!\d)/, $path ) {
     my ($step, $index) = split /\./, $step_index;
     if ($cur_class->can($step)) {
-      if ($cur_class->meta->relationship($step)) { #a
-        my $next_class = $cur_class->meta->relationship($step)->class;
-        push @{ $spec->{steps} }, [ $step, $next_class, $index ];
-        $cur_class = $next_class;
+      if (my $rel = $cur_class->meta->relationship($step)) { #a
+        if ($index && ! $rel->isa('Rose::DB::Object::Metadata::Relationship::OneToMany')) {
+          $self->_push_error([
+            $path,
+            undef,
+            "Profile path error. Indexed relationship is not OneToMany around here: '$step_index'",
+            undef,
+            0,
+          ]);
+          return;
+        } else {
+          my $next_class = $cur_class->meta->relationship($step)->class;
+          push @{ $spec->{steps} }, [ $step, $next_class, $index ];
+          $cur_class = $next_class;
+          eval "require $cur_class; 1" or die "could not load class '$cur_class'";
+        }
       } else { # simple dispatch
         push @{ $spec->{steps} }, [ $step ];
         last;
@@ -126,7 +149,7 @@ sub errors {
 
 sub _push_error {
   my ($self, @errors) = @_;
-  my @new_errors = ($self->errors, @errors);
+  my @new_errors = ($self->errors, map { SL::Helper::Csv::Error->new(@$_) } @errors);
   $self->_errors(\@new_errors);
 }