re-work importer to allow new sources and targets to be implemented
[bse.git] / site / cgi-bin / modules / BSE / ImportTargetArticle.pm
CommitLineData
3709451d
TC
1package BSE::ImportTargetArticle;
2use strict;
3use base 'BSE::ImportTargetBase';
4use BSE::API qw(bse_make_article bse_add_image bse_add_step_parent);
5use Articles;
6use Products;
7use OtherParents;
8
9sub new {
10 my ($class, %opts) = @_;
11
12 my $self = $class->SUPER::new(%opts);
13
14 my $importer = delete $opts{importer};
15
16 my $map = $importer->maps;
17 defined $map->{title}
18 or die "No title mapping found\n";
19
20 $self->{use_codes} = $importer->cfg_entry('codes', 0);
21 $self->{code_field} = $importer->cfg_entry("code_field", $self->default_code_field);
22
23 $self->{parent} = $importer->cfg_entry("parent", $self->default_parent);
24
25 if ($self->{use_codes} && !defined $map->{$self->{code_field}}) {
26 die "No product_code mapping found with 'codes' enabled\n";
27 }
28 $self->{ignore_missing} = $importer->cfg_entry("ignore_missing", 1);
29 $self->{reset_images} = $importer->cfg_entry("reset_images", 0);
30 $self->{reset_steps} = $importer->cfg_entry("reset_steps", 0);
31
32 return $self;
33}
34
35sub start {
36 my ($self) = @_;
37
38 $self->{parent_cache} = {};
39 $self->{leaves} = [];
40 $self->{parents} = [];
41}
42
43sub xform_entry {
44 my ($self, $importer, $entry) = @_;
45
46 defined $entry->{template}
47 or $entry->{template} = $self->leaf_template;
48
49 $entry->{title} =~ /\S/
50 or die "title blank\n";
51
52 $entry->{title} =~ /\n/
53 and die "Title may not contain newlines";
54 $entry->{summary}
55 or $entry->{summary} = $entry->{title};
56 $entry->{description}
57 or $entry->{description} = $entry->{title};
58 $entry->{body}
59 or $entry->{body} = $entry->{title};
60}
61
62sub children_of {
63 my ($self, $parent) = @_;
64
65 Articles->children($parent);
66}
67
68sub make_parent {
69 my ($self, $importer, %entry) = @_;
70
71 return bse_make_article(%entry);
72}
73
74sub find_leaf {
75 my ($self, $leaf_id) = @_;
76
77 $leaf_id =~ tr/A-Za-z0-9_/_/cds;
78
79 my ($leaf) = Articles->getBy($self->{code_field}, $leaf_id)
80 or return;
81
82 return $leaf;
83}
84
85sub make_leaf {
86 my ($self, $importer, %entry) = @_;
87
88 return bse_make_article(%entry);
89}
90
91sub row {
92 my ($self, $importer, $entry, $parents) = @_;
93
94
95 $entry->{parentid} = $self->_find_parent($importer, $self->{parent}, @$parents);
96 my $leaf;
97 if ($self->{use_codes}) {
98 my $leaf_id = $entry->{$self->{code_field}};
99
100 $leaf = $self->find_leaf($leaf_id);
101 }
102 if ($leaf) {
103 @{$leaf}{keys %$entry} = values %$entry;
104 $leaf->save;
105 $importer->info("Updated $leaf->{id}: $entry->{title}");
106 if ($self->{reset_images}) {
107 $leaf->remove_images($importer->cfg);
108 $importer->info(" $leaf->{id}: Reset images");
109 }
110 if ($self->{reset_steps}) {
111 my @steps = OtherParents->getBy(childId => $leaf->{id});
112 for my $step (@steps) {
113 $step->remove;
114 }
115 }
116 }
117 else {
118 $leaf = $self->make_leaf
119 (
120 $importer,
121 cfg => $importer->cfg,
122 %$entry
123 );
124 $importer->info("Added $leaf->{id}: $entry->{title}");
125 }
126 for my $image_index (1 .. 10) {
127 my $file = $entry->{"image${image_index}_file"};
128 $file
129 or next;
130 my $full_file = $importer->find_file($file);
131
132 unless ($full_file) {
133 $self->{ignore_missing}
134 and next;
135 die "File '$file' not found for image$image_index\n";
136 }
137
138 my %opts = ( file => $full_file );
139 for my $key (qw/alt name url storage/) {
140 my $fkey = "image${image_index}_$key";
141 $entry->{$fkey}
142 and $opts{$key} = $entry->{$fkey};
143 }
144
145 my %errors;
146 my $im = bse_add_image($importer->cfg, $leaf, %opts,
147 errors => \%errors);
148 $im
149 or die join(", ",map "$_: $errors{$_}", keys %errors), "\n";
150 $importer->info(" $leaf->{id}: Add image '$file'");
151 }
152 for my $step_index (1 .. 10) {
153 my $step_id = $entry->{"step$step_index"};
154 $step_id
155 or next;
156 my $step;
157 if ($step_id =~ /^\d+$/) {
158 $step = Articles->getByPkey($step_id);
159 }
160 else {
161 $step = Articles->getBy(linkAlias => $step_id);
162 }
163 $step
164 or die "Cannot find stepparent with id $step_id\n";
165
166 bse_add_step_parent($importer->cfg, child => $leaf, parent => $step);
167 }
168 push @{$self->{leaves}}, $leaf;
169}
170
171sub _find_parent {
172 my ($self, $importer, $parent, @parents) = @_;
173
174 @parents
175 or return $parent;
176 my $cache = $self->{parent_cache};
177 unless ($cache->{$parent}) {
178 my @kids = $self->children_of($parent);
179 $cache->{$parent} = \@kids;
180 }
181
182 my $title = shift @parents;
183 my ($cat) = grep lc $_->{title} eq lc $title, @{$cache->{$parent}};
184 unless ($cat) {
185 my %opts =
186 (
187 cfg => $importer->cfg,
188 parentid => $parent,
189 title => $title,
190 body => $title,
191 );
192 $self->{catalog_template}
193 and $opts{template} = $self->{catalog_template};
194 $cat = $self->make_parent($importer, %opts);
195 $importer->info("Add parent $cat->{id}: $title");
196 push @{$cache->{$parent}}, $cat;
197 }
198
199 unless ($self->{catseen}{$cat->{id}}) {
200 $self->{catseen}{$cat->{id}} = 1;
201 push @{$self->{parents}}, $cat;
202 }
203
204 return $self->_find_parent($importer, $cat->{id}, @parents);
205}
206
207sub default_parent { -1 }
208
209sub default_code_field { "linkAlias" }
210
211sub leaves {
212 return @{$_[0]{leaves}}
213}
214
215sub parents {
216 return @{$_[0]{parents}}
217}
218
2191;