1 | <?php |
---|
2 | |
---|
3 | |
---|
4 | // Update mode for existing items. |
---|
5 | define('FEEDS_SKIP_EXISTING', 0); |
---|
6 | define('FEEDS_REPLACE_EXISTING', 1); |
---|
7 | define('FEEDS_UPDATE_EXISTING', 2); |
---|
8 | |
---|
9 | /** |
---|
10 | * Abstract class, defines interface for processors. |
---|
11 | */ |
---|
12 | abstract class FeedsProcessor extends FeedsPlugin { |
---|
13 | |
---|
14 | /** |
---|
15 | * Process the result of the parser or previous processors. |
---|
16 | * Extending classes must implement this method. |
---|
17 | * |
---|
18 | * @param FeedsImportBatch $batch |
---|
19 | * The current feed import data passed in from the parsing stage. |
---|
20 | * @param FeedsSource $source |
---|
21 | * Source information about this import. |
---|
22 | */ |
---|
23 | public abstract function process(FeedsImportBatch $batch, FeedsSource $source); |
---|
24 | |
---|
25 | /** |
---|
26 | * Remove all stored results or stored results up to a certain time for this |
---|
27 | * configuration/this source. |
---|
28 | * |
---|
29 | * @param FeedsBatch $batch |
---|
30 | * A FeedsBatch object for tracking information such as how many |
---|
31 | * items have been deleted total between page loads. |
---|
32 | * @param FeedsSource $source |
---|
33 | * Source information for this expiry. Implementers should only delete items |
---|
34 | * pertaining to this source. The preferred way of determining whether an |
---|
35 | * item pertains to a certain souce is by using $source->feed_nid. It is the |
---|
36 | * processor's responsibility to store the feed_nid of an imported item in |
---|
37 | * the processing stage. |
---|
38 | */ |
---|
39 | public abstract function clear(FeedsBatch $batch, FeedsSource $source); |
---|
40 | |
---|
41 | /** |
---|
42 | * Delete feed items younger than now - $time. Do not invoke expire on a |
---|
43 | * processor directly, but use FeedsImporter::expire() instead. |
---|
44 | * |
---|
45 | * @see FeedsImporter::expire(). |
---|
46 | * @see FeedsDataProcessor::expire(). |
---|
47 | * |
---|
48 | * @param $time |
---|
49 | * If implemented, all items produced by this configuration that are older |
---|
50 | * than FEEDS_REQUEST_TIME - $time should be deleted. |
---|
51 | * If $time === NULL processor should use internal configuration. |
---|
52 | * |
---|
53 | * @return |
---|
54 | * FEEDS_BATCH_COMPLETE if all items have been processed, a float between 0 |
---|
55 | * and 0.99* indicating progress otherwise. |
---|
56 | */ |
---|
57 | public function expire($time = NULL) { |
---|
58 | return FEEDS_BATCH_COMPLETE; |
---|
59 | } |
---|
60 | |
---|
61 | /** |
---|
62 | * Execute mapping on an item. |
---|
63 | * |
---|
64 | * This method encapsulates the central mapping functionality. When an item is |
---|
65 | * processed, it is passed through map() where the properties of $source_item |
---|
66 | * are mapped onto $target_item following the processor's mapping |
---|
67 | * configuration. |
---|
68 | * |
---|
69 | * For each mapping FeedsParser::getSourceElement() is executed to retrieve |
---|
70 | * the source element, then FeedsProcessor::setTargetElement() is invoked |
---|
71 | * to populate the target item properly. Alternatively a |
---|
72 | * hook_x_targets_alter() may have specified a callback for a mapping target |
---|
73 | * in which case the callback is asked to populate the target item instead of |
---|
74 | * FeedsProcessor::setTargetElement(). |
---|
75 | * |
---|
76 | * @ingroup mappingapi |
---|
77 | * |
---|
78 | * @see hook_feeds_parser_sources_alter() |
---|
79 | * @see hook_feeds_data_processor_targets_alter() |
---|
80 | * @see hook_feeds_node_processor_targets_alter() |
---|
81 | * @see hook_feeds_term_processor_targets_alter() |
---|
82 | * @see hook_feeds_user_processor_targets_alter() |
---|
83 | */ |
---|
84 | protected function map(FeedsImportBatch $batch, $target_item = NULL) { |
---|
85 | |
---|
86 | // Static cache $targets as getMappingTargets() may be an expensive method. |
---|
87 | static $sources; |
---|
88 | if (!isset($sources[$this->id])) { |
---|
89 | $sources[$this->id] = feeds_importer($this->id)->parser->getMappingSources(); |
---|
90 | } |
---|
91 | static $targets; |
---|
92 | if (!isset($targets[$this->id])) { |
---|
93 | $targets[$this->id] = $this->getMappingTargets(); |
---|
94 | } |
---|
95 | $parser = feeds_importer($this->id)->parser; |
---|
96 | if (empty($target_item)) { |
---|
97 | $target_item = array(); |
---|
98 | } |
---|
99 | |
---|
100 | // Many mappers add to existing fields rather than replacing them. Hence we |
---|
101 | // need to clear target elements of each item before mapping in case we are |
---|
102 | // mapping on a prepopulated item such as an existing node. |
---|
103 | $convert_to_array = FALSE; |
---|
104 | if (is_array($target_item)) { |
---|
105 | $target_item = (object)$target_item; |
---|
106 | $convert_to_array = TRUE; |
---|
107 | } |
---|
108 | foreach ($this->config['mappings'] as $mapping) { |
---|
109 | if (isset($targets[$this->id][$mapping['target']]['real_target'])) { |
---|
110 | unset($target_item->{$targets[$this->id][$mapping['target']]['real_target']}); |
---|
111 | } |
---|
112 | elseif (isset($target_item->{$mapping['target']})) { |
---|
113 | unset($target_item->{$mapping['target']}); |
---|
114 | } |
---|
115 | } |
---|
116 | if ($convert_to_array) { |
---|
117 | $target_item = (array)$target_item; |
---|
118 | } |
---|
119 | |
---|
120 | /* |
---|
121 | This is where the actual mapping happens: For every mapping we envoke |
---|
122 | the parser's getSourceElement() method to retrieve the value of the source |
---|
123 | element and pass it to the processor's setTargetElement() to stick it |
---|
124 | on the right place of the target item. |
---|
125 | |
---|
126 | If the mapping specifies a callback method, use the callback instead of |
---|
127 | setTargetElement(). |
---|
128 | */ |
---|
129 | self::loadMappers(); |
---|
130 | foreach ($this->config['mappings'] as $mapping) { |
---|
131 | // Retrieve source element's value from parser. |
---|
132 | if (is_array($sources[$this->id][$mapping['source']]) && |
---|
133 | isset($sources[$this->id][$mapping['source']]['callback']) && |
---|
134 | function_exists($sources[$this->id][$mapping['source']]['callback'])) { |
---|
135 | $callback = $sources[$this->id][$mapping['source']]['callback']; |
---|
136 | $value = $callback($batch, $mapping['source']); |
---|
137 | } |
---|
138 | else { |
---|
139 | $value = $parser->getSourceElement($batch, $mapping['source']); |
---|
140 | } |
---|
141 | |
---|
142 | // Map the source element's value to the target. |
---|
143 | if (is_array($targets[$this->id][$mapping['target']]) && |
---|
144 | isset($targets[$this->id][$mapping['target']]['callback']) && |
---|
145 | function_exists($targets[$this->id][$mapping['target']]['callback'])) { |
---|
146 | $callback = $targets[$this->id][$mapping['target']]['callback']; |
---|
147 | $callback($target_item, $mapping['target'], $value); |
---|
148 | } |
---|
149 | else { |
---|
150 | $this->setTargetElement($target_item, $mapping['target'], $value); |
---|
151 | } |
---|
152 | } |
---|
153 | return $target_item; |
---|
154 | } |
---|
155 | |
---|
156 | /** |
---|
157 | * Per default, don't support expiry. If processor supports expiry of imported |
---|
158 | * items, return the time after which items should be removed. |
---|
159 | */ |
---|
160 | public function expiryTime() { |
---|
161 | return FEEDS_EXPIRE_NEVER; |
---|
162 | } |
---|
163 | |
---|
164 | /** |
---|
165 | * Declare default configuration. |
---|
166 | */ |
---|
167 | public function configDefaults() { |
---|
168 | return array('mappings' => array()); |
---|
169 | } |
---|
170 | |
---|
171 | /** |
---|
172 | * Get mappings. |
---|
173 | */ |
---|
174 | public function getMappings() { |
---|
175 | return isset($this->config['mappings']) ? $this->config['mappings'] : array(); |
---|
176 | } |
---|
177 | |
---|
178 | /** |
---|
179 | * Declare possible mapping targets that this processor exposes. |
---|
180 | * |
---|
181 | * @ingroup mappingapi |
---|
182 | * |
---|
183 | * @return |
---|
184 | * An array of mapping targets. Keys are paths to targets |
---|
185 | * separated by ->, values are TRUE if target can be unique, |
---|
186 | * FALSE otherwise. |
---|
187 | */ |
---|
188 | public function getMappingTargets() { |
---|
189 | return array(); |
---|
190 | } |
---|
191 | |
---|
192 | /** |
---|
193 | * Set a concrete target element. Invoked from FeedsProcessor::map(). |
---|
194 | * |
---|
195 | * @ingroup mappingapi |
---|
196 | */ |
---|
197 | public function setTargetElement(&$target_item, $target_element, $value) { |
---|
198 | $target_item[$target_element] = $value; |
---|
199 | } |
---|
200 | |
---|
201 | /** |
---|
202 | * Retrieve the target item's existing id if available. Otherwise return 0. |
---|
203 | * |
---|
204 | * @ingroup mappingapi |
---|
205 | * |
---|
206 | * @param $batch |
---|
207 | * A FeedsImportBatch object. |
---|
208 | * @param FeedsSource $source |
---|
209 | * The source information about this import. |
---|
210 | */ |
---|
211 | protected function existingItemId(FeedsImportBatch $batch, FeedsSource $source) { |
---|
212 | return 0; |
---|
213 | } |
---|
214 | |
---|
215 | /** |
---|
216 | * Utility function that iterates over a target array and retrieves all |
---|
217 | * sources that are unique. |
---|
218 | * |
---|
219 | * @param $batch |
---|
220 | * A FeedsImportBatch. |
---|
221 | * |
---|
222 | * @return |
---|
223 | * An array where the keys are target field names and the values are the |
---|
224 | * elements from the source item mapped to these targets. |
---|
225 | */ |
---|
226 | protected function uniqueTargets(FeedsImportBatch $batch) { |
---|
227 | $parser = feeds_importer($this->id)->parser; |
---|
228 | $targets = array(); |
---|
229 | foreach ($this->config['mappings'] as $mapping) { |
---|
230 | if ($mapping['unique']) { |
---|
231 | // Invoke the parser's getSourceElement to retrieve the value for this |
---|
232 | // mapping's source. |
---|
233 | $targets[$mapping['target']] = $parser->getSourceElement($batch, $mapping['source']); |
---|
234 | } |
---|
235 | } |
---|
236 | return $targets; |
---|
237 | } |
---|
238 | } |
---|