Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 17d58914

Von Sven Schöling vor mehr als 13 Jahren hinzugefügt

  • ID 17d58914b5dbaf021dcea3375ee943bb6e798916
  • Vorgänger 1dcc096b
  • Nachfolger 417cc3a7

Csv Dispatcher implementiert.

Unterschiede anzeigen:

SL/Helper/Csv.pm
5 5

  
6 6
use Carp;
7 7
use IO::File;
8
use Text::CSV;
9 8
use Params::Validate qw(:all);
9
use Text::CSV;
10 10
use Rose::Object::MakeMethods::Generic scalar => [ qw(
11 11
  file encoding sep_char quote_char escape_char header profile class
12 12
  numberformat dateformat ignore_unknown_columns _io _csv _objects _parsed
13 13
  _data _errors
14 14
) ];
15 15

  
16
use SL::Helper::Csv::Dispatcher;
16 17

  
17 18
# public interface
18 19

  
......
53 54

  
54 55
  $self->_open_file;
55 56
  return if ! $self->_check_header;
56
  return if $self->class && ! $self->_check_header_for_class;
57
  return if ! $self->dispatcher->parse_profile;
58
#  return if $self->class && ! $self->_check_header_for_class;
57 59
  return if ! $self->_parse_data;
58 60

  
59 61
  $self->_parsed(1);
......
109 111
  $self->header($header);
110 112
}
111 113

  
112
sub _check_header_for_class {
113
  my ($self, %params) = @_;
114
  my @errors;
115

  
116
  carp 'this should never be called without' unless $self->class;
117

  
118
  if ($self->ignore_unknown_columns) {
119
    my @new_header;
120
    for my $method (@{ $self->header }) {
121
      push @new_header, $self->class->can($self->_real_method($method))
122
         ? $method : undef;
123
    }
124

  
125
    $self->header(\@new_header);
126

  
127
    return 1;
128
  } else {
129
    for my $method (@{ $self->header }) {
130
      next if ! $method;
131
      next if $self->class->can($self->_real_method($method));
132

  
133
      push @errors, [
134
        $method,
135
        undef,
136
        "header field $method is not recognized",
137
        undef,
138
        0,
139
      ];
140
    }
141

  
142
    $self->_push_error(@errors);
143
    return ! @errors;
144
  }
145
}
146

  
147 114
sub _parse_data {
148 115
  my ($self, %params) = @_;
149 116
  my (@data, @errors);
......
153 120
  while (1) {
154 121
    my $row = $self->_csv->getline($self->_io);
155 122
    last if $self->_csv->eof;
156

  
157 123
    if ($row) {
158 124
      my %hr;
159 125
      @hr{@{ $self->header }} = @$row;
......
186 152
  local $::myconfig{dateformat}   = $self->dateformat   if $self->dateformat;
187 153

  
188 154
  for my $line (@{ $self->_data }) {
189
    push @objs, $self->class->new(
190
      map {
191
        $self->_real_method($_) => $line->{$_}
192
      } grep { $_ } keys %$line
193
    );
155
    my $tmp_obj = $self->class->new;
156
    $self->dispatcher->dispatch($tmp_obj, $line);
157
    push @objs, $tmp_obj;
194 158
  }
195 159

  
196 160
  $self->_objects(\@objs);
197 161
}
198 162

  
199
sub _real_method {
200
  my ($self, $arg) = @_;
201
  ($self->profile && $self->profile->{$arg}) || $arg;
163
sub dispatcher {
164
  my ($self, %params) = @_;
165

  
166
  $self->{_dispatcher} ||= $self->_make_dispatcher;
167
}
168

  
169
sub _make_dispatcher {
170
  my ($self, %params) = @_;
171

  
172
  die 'need a header to make a dispatcher' unless $self->header;
173

  
174
  return SL::Helper::Csv::Dispatcher->new($self);
202 175
}
203 176

  
204 177
sub _guess_encoding {
SL/Helper/Csv/Dispatcher.pm
1
package SL::Helper::Csv::Dispatcher;
2

  
3
use strict;
4

  
5
use Data::Dumper;
6
use Carp;
7
use Scalar::Util qw(weaken);
8
use Rose::Object::MakeMethods::Generic scalar => [ qw(
9
  _specs _errors
10
) ];
11

  
12
sub new {
13
  my ($class, $parent) = @_;
14
  my $self = bless { }, $class;
15

  
16
  weaken($self->{_csv} = $parent);
17
  $self->_errors([]);
18

  
19
  return $self;
20
}
21

  
22
sub dispatch {
23
  my ($self, $obj, $line) = @_;
24

  
25
  for my $spec (@{ $self->_specs }) {
26
    $self->apply($obj, $spec, $line->{$spec->{key}});
27
  }
28
}
29

  
30
sub apply {
31
  my ($self, $obj, $spec, $value) = @_;
32
  return unless $value;
33

  
34
  for my $step (@{ $spec->{steps} }) {
35
    my ($acc, $class) = @$step;
36
    if ($class) {
37
      eval "require $class; 1" or die "could not load class '$class'";
38
      $obj->$acc($class->new) if ! $$obj->$acc;
39
      $obj = $obj->$acc;
40
    } else {
41
      $obj->$acc($value);
42
    }
43
  }
44
}
45

  
46
sub is_known {
47
  my ($self, $col) = @_;
48
  return grep { $col eq $_->{key} } $self->_specs;
49
}
50

  
51
sub parse_profile {
52
  my ($self, %params) = @_;
53

  
54
  my $header  = $self->_csv->header;
55
  my $profile = $self->_csv->profile;
56
  my @specs;
57

  
58
  for my $col (@$header) {
59
    next unless $col;
60
    push @specs, $self->make_spec($col, $profile->{$col} || $col);
61
  }
62

  
63
  $self->_specs(\@specs);
64
  $self->_csv->_push_error($self->errors);
65
  return ! $self->errors;
66
}
67

  
68
sub make_spec {
69
  my ($self, $col, $path) = @_;
70

  
71
  my $spec = { key => $col, steps => [] };
72
  my $cur_class = $self->_csv->class;
73

  
74
  for my $step ( split /\./, $path ) {
75
    if ($cur_class->can($step)) {
76
      if ($cur_class->meta->relationship($step)) { #a
77
        my $next_class = $cur_class->meta->relationsship($step)->class;
78
        push @{ $spec->{steps} }, [ $step, $next_class ];
79
        $cur_class = $next_class;
80
      } else { # simple dispatch
81
        push @{ $spec->{steps} }, [ $step ];
82
        last;
83
      }
84
    } else {
85
      $self->unknown_column($col, $path);
86
    }
87
  }
88

  
89
  return $spec;
90
}
91

  
92
sub unknown_column {
93
  my ($self, $col, $path) = @_;
94
  return if $self->_csv->ignore_unknown_columns;
95

  
96
  $self->_push_error([
97
    $col,
98
    undef,
99
    "header field '$col' is not recognized",
100
    undef,
101
    0,
102
  ]);
103
}
104

  
105
sub _csv {
106
  $_[0]->{_csv};
107
}
108

  
109
sub errors {
110
  @{ $_[0]->_errors }
111
}
112

  
113
sub _push_error {
114
  my ($self, @errors) = @_;
115
  my @new_errors = ($self->errors, @errors);
116
  $self->_errors(\@new_errors);
117
}
118

  
119
1;

Auch abrufbar als: Unified diff