1 |
85ad3d82
|
Assos Assos
|
<?php
|
2 |
|
|
|
3 |
|
|
/**
|
4 |
|
|
* @file
|
5 |
|
|
* Contains all page callbacks, forms and theming functions for Feeds
|
6 |
|
|
* administrative pages.
|
7 |
|
|
*/
|
8 |
|
|
|
9 |
|
|
/**
|
10 |
|
|
* Introductory help for admin/structure/feeds/%feeds_importer page
|
11 |
|
|
*/
|
12 |
|
|
function feeds_ui_edit_help() {
|
13 |
|
|
return t('
|
14 |
|
|
<p>
|
15 |
|
|
You can create as many Feeds importer configurations as you would like to. Each can have a distinct purpose like letting your users aggregate RSS feeds or importing a CSV file for content migration. Here are a couple of things that are important to understand in order to get started with Feeds:
|
16 |
|
|
</p>
|
17 |
|
|
<ul>
|
18 |
|
|
<li>
|
19 |
|
|
Every importer configuration consists of basic settings, a fetcher, a parser and a processor and their settings.
|
20 |
|
|
</li>
|
21 |
|
|
<li>
|
22 |
|
|
The <strong>basic settings</strong> define the general behavior of the importer. <strong>Fetchers</strong> are responsible for loading data, <strong>parsers</strong> for organizing it and <strong>processors</strong> for "doing stuff" with it, usually storing it.
|
23 |
|
|
</li>
|
24 |
|
|
<li>
|
25 |
|
|
In Basic settings, you can <strong>attach an importer configuration to a content type</strong>. This is useful when many imports of a kind should be created, for example in an RSS aggregation scenario. If you don\'t attach a configuration to a content type, you can use it on the !import page.
|
26 |
|
|
</li>
|
27 |
|
|
<li>
|
28 |
|
|
Imports can be <strong>scheduled periodically</strong> - see the periodic import select box in the Basic settings.
|
29 |
|
|
</li>
|
30 |
|
|
<li>
|
31 |
|
|
Processors can have <strong>mappings</strong> in addition to settings. Mappings allow you to define what elements of a data feed should be mapped to what content fields on a granular level. For instance, you can specify that a feed item\'s author should be mapped to a node\'s body.
|
32 |
|
|
</li>
|
33 |
|
|
</ul>
|
34 |
|
|
', array('!import' => l(t('Import'), 'import')));
|
35 |
|
|
}
|
36 |
|
|
|
37 |
|
|
/**
|
38 |
|
|
* Help text for mapping.
|
39 |
|
|
*/
|
40 |
|
|
function feeds_ui_mapping_help() {
|
41 |
|
|
return t('
|
42 |
|
|
<p>
|
43 |
|
|
Define which elements of a single item of a feed (= <em>Sources</em>) map to which content pieces in Drupal (= <em>Targets</em>). Make sure that at least one definition has a <em>Unique target</em>. A unique target means that a value for a target can only occur once. E. g. only one item with the URL <em>http://example.com/content/1</em> can exist.
|
44 |
|
|
</p>
|
45 |
|
|
');
|
46 |
|
|
}
|
47 |
|
|
|
48 |
|
|
/**
|
49 |
|
|
* Build overview of available configurations.
|
50 |
|
|
*/
|
51 |
|
|
function feeds_ui_overview_form($form, &$form_status) {
|
52 |
|
|
$form = $form['enabled'] = $form['disabled'] = array();
|
53 |
|
|
|
54 |
|
|
$form['#header'] = array(
|
55 |
|
|
t('Name'),
|
56 |
|
|
t('Description'),
|
57 |
|
|
t('Attached to'),
|
58 |
|
|
t('Status'),
|
59 |
|
|
t('Operations'),
|
60 |
|
|
t('Enabled'),
|
61 |
|
|
);
|
62 |
|
|
foreach (feeds_importer_load_all(TRUE) as $importer) {
|
63 |
|
|
$importer_form = array();
|
64 |
|
|
$importer_form['name']['#markup'] = check_plain($importer->config['name']);
|
65 |
|
|
$importer_form['description']['#markup'] = check_plain($importer->config['description']);
|
66 |
|
|
if (empty($importer->config['content_type'])) {
|
67 |
|
|
$importer_form['attached']['#markup'] = '[none]';
|
68 |
|
|
}
|
69 |
|
|
else {
|
70 |
|
|
if (!$importer->disabled) {
|
71 |
|
|
$importer_form['attached']['#markup'] = l(node_type_get_name($importer->config['content_type']), 'node/add/' . str_replace('_', '-', $importer->config['content_type']));
|
72 |
|
|
}
|
73 |
|
|
else {
|
74 |
|
|
$importer_form['attached']['#markup'] = check_plain(node_type_get_name($importer->config['content_type']));
|
75 |
|
|
}
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
if ($importer->export_type == EXPORT_IN_CODE) {
|
79 |
|
|
$status = t('Default');
|
80 |
|
|
$edit = t('Override');
|
81 |
|
|
$delete = '';
|
82 |
|
|
}
|
83 |
|
|
elseif ($importer->export_type == EXPORT_IN_DATABASE) {
|
84 |
|
|
$status = t('Normal');
|
85 |
|
|
$edit = t('Edit');
|
86 |
|
|
$delete = t('Delete');
|
87 |
|
|
}
|
88 |
|
|
elseif ($importer->export_type == (EXPORT_IN_CODE | EXPORT_IN_DATABASE)) {
|
89 |
|
|
$status = t('Overridden');
|
90 |
|
|
$edit = t('Edit');
|
91 |
|
|
$delete = t('Revert');
|
92 |
|
|
}
|
93 |
|
|
$importer_form['status'] = array(
|
94 |
|
|
'#markup' => $status,
|
95 |
|
|
);
|
96 |
|
|
$importer_form['operations'] = array(
|
97 |
|
|
'#markup' =>
|
98 |
|
|
l($edit, 'admin/structure/feeds/' . $importer->id) . ' | ' .
|
99 |
|
|
l(t('Export'), 'admin/structure/feeds/' . $importer->id . '/export') . ' | ' .
|
100 |
|
|
l(t('Clone'), 'admin/structure/feeds/' . $importer->id . '/clone') .
|
101 |
|
|
(empty($delete) ? '' : ' | ' . l($delete, 'admin/structure/feeds/' . $importer->id . '/delete')),
|
102 |
|
|
);
|
103 |
|
|
|
104 |
|
|
$importer_form[$importer->id] = array(
|
105 |
|
|
'#type' => 'checkbox',
|
106 |
|
|
'#default_value' => !$importer->disabled,
|
107 |
|
|
);
|
108 |
|
|
|
109 |
|
|
if ($importer->disabled) {
|
110 |
|
|
$form['disabled'][$importer->id] = $importer_form;
|
111 |
|
|
}
|
112 |
|
|
else {
|
113 |
|
|
$form['enabled'][$importer->id] = $importer_form;
|
114 |
|
|
}
|
115 |
|
|
}
|
116 |
|
|
$form['submit'] = array(
|
117 |
|
|
'#type' => 'submit',
|
118 |
|
|
'#value' => t('Save'),
|
119 |
|
|
);
|
120 |
|
|
return $form;
|
121 |
|
|
}
|
122 |
|
|
|
123 |
|
|
/**
|
124 |
|
|
* Submit handler for feeds_ui_overview_form().
|
125 |
|
|
*/
|
126 |
|
|
function feeds_ui_overview_form_submit($form, &$form_state) {
|
127 |
|
|
|
128 |
|
|
$disabled = array();
|
129 |
|
|
foreach (feeds_importer_load_all(TRUE) as $importer) {
|
130 |
|
|
$disabled[$importer->id] = !$form_state['values'][$importer->id];
|
131 |
|
|
}
|
132 |
|
|
variable_set('default_feeds_importer', $disabled);
|
133 |
|
|
feeds_cache_clear();
|
134 |
|
|
}
|
135 |
|
|
|
136 |
|
|
/**
|
137 |
|
|
* Create a new configuration.
|
138 |
|
|
*
|
139 |
|
|
* @param $form_state
|
140 |
|
|
* Form API form state array.
|
141 |
|
|
* @param $from_importer
|
142 |
|
|
* FeedsImporter object. If given, form will create a new importer as a copy
|
143 |
|
|
* of $from_importer.
|
144 |
|
|
*/
|
145 |
|
|
function feeds_ui_create_form($form, &$form_state, $from_importer = NULL) {
|
146 |
|
|
$form['#from_importer'] = $from_importer;
|
147 |
|
|
$form['name'] = array(
|
148 |
|
|
'#type' => 'textfield',
|
149 |
|
|
'#title' => t('Name'),
|
150 |
|
|
'#description' => t('A natural name for this configuration. Example: RSS Feed. You can always change this name later.'),
|
151 |
|
|
'#required' => TRUE,
|
152 |
|
|
'#maxlength' => 128,
|
153 |
|
|
);
|
154 |
|
|
$form['id'] = array(
|
155 |
|
|
'#type' => 'machine_name',
|
156 |
|
|
'#required' => TRUE,
|
157 |
|
|
'#maxlength' => 128,
|
158 |
|
|
'#machine_name' => array(
|
159 |
|
|
'exists' => 'feeds_ui_importer_machine_name_exists',
|
160 |
|
|
),
|
161 |
|
|
);
|
162 |
|
|
$form['description'] = array(
|
163 |
|
|
'#type' => 'textfield',
|
164 |
|
|
'#title' => t('Description'),
|
165 |
|
|
'#description' => t('A description of this configuration.'),
|
166 |
|
|
);
|
167 |
|
|
$form['submit'] = array(
|
168 |
|
|
'#type' => 'submit',
|
169 |
|
|
'#value' => t('Create'),
|
170 |
|
|
);
|
171 |
|
|
return $form;
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
/**
|
175 |
|
|
* Validation callback for the importer machine name field.
|
176 |
|
|
*/
|
177 |
|
|
function feeds_ui_importer_machine_name_exists($id) {
|
178 |
|
|
if ($id == 'create') {
|
179 |
|
|
// Create is a reserved path for the add importer form.
|
180 |
|
|
return TRUE;
|
181 |
|
|
}
|
182 |
|
|
ctools_include('export');
|
183 |
|
|
if (ctools_export_load_object('feeds_importer', 'conditions', array('id' => $id))) {
|
184 |
|
|
return TRUE;
|
185 |
|
|
}
|
186 |
|
|
}
|
187 |
|
|
|
188 |
|
|
/**
|
189 |
|
|
* Validation handler for feeds_build_create_form().
|
190 |
|
|
*/
|
191 |
|
|
function feeds_ui_create_form_validate($form, &$form_state) {
|
192 |
|
|
if (!empty($form_state['values']['id'])) {
|
193 |
|
|
$importer = feeds_importer($form_state['values']['id']);
|
194 |
|
|
$importer->configFormValidate($form_state['values']);
|
195 |
|
|
}
|
196 |
|
|
}
|
197 |
|
|
|
198 |
|
|
/**
|
199 |
|
|
* Submit handler for feeds_build_create_form().
|
200 |
|
|
*/
|
201 |
|
|
function feeds_ui_create_form_submit($form, &$form_state) {
|
202 |
|
|
// Create feed.
|
203 |
|
|
$importer = feeds_importer($form_state['values']['id']);
|
204 |
|
|
// If from_importer is given, copy its configuration.
|
205 |
|
|
if (!empty($form['#from_importer'])) {
|
206 |
|
|
$importer->copy($form['#from_importer']);
|
207 |
|
|
}
|
208 |
|
|
// In any case, we want to set this configuration's title and description.
|
209 |
|
|
$importer->addConfig($form_state['values']);
|
210 |
|
|
$importer->save();
|
211 |
|
|
|
212 |
|
|
// Set a message and redirect to settings form.
|
213 |
|
|
if (empty($form['#from_importer'])) {
|
214 |
|
|
drupal_set_message(t('Your configuration has been created with default settings. If they do not fit your use case you can adjust them here.'));
|
215 |
|
|
}
|
216 |
|
|
else {
|
217 |
|
|
drupal_set_message(t('A clone of the @name configuration has been created.', array('@name' => $form['#from_importer']->config['name'])));
|
218 |
|
|
}
|
219 |
|
|
$form_state['redirect'] = 'admin/structure/feeds/' . $importer->id;
|
220 |
|
|
feeds_cache_clear();
|
221 |
|
|
}
|
222 |
|
|
|
223 |
|
|
/**
|
224 |
|
|
* Delete configuration form.
|
225 |
|
|
*/
|
226 |
|
|
function feeds_ui_delete_form($form, &$form_state, $importer) {
|
227 |
|
|
$form['#importer'] = $importer->id;
|
228 |
|
|
if ($importer->export_type & EXPORT_IN_CODE) {
|
229 |
|
|
$title = t('Would you really like to revert the importer @importer?', array('@importer' => $importer->config['name']));
|
230 |
|
|
$button_label = t('Revert');
|
231 |
|
|
}
|
232 |
|
|
else {
|
233 |
|
|
$title = t('Would you really like to delete the importer @importer?', array('@importer' => $importer->config['name']));
|
234 |
|
|
$button_label = t('Delete');
|
235 |
|
|
}
|
236 |
|
|
return confirm_form(
|
237 |
|
|
$form,
|
238 |
|
|
$title,
|
239 |
|
|
'admin/structure/feeds',
|
240 |
|
|
t('This action cannot be undone.'),
|
241 |
|
|
$button_label
|
242 |
|
|
);
|
243 |
|
|
}
|
244 |
|
|
|
245 |
|
|
/**
|
246 |
|
|
* Submit handler for feeds_ui_delete_form().
|
247 |
|
|
*/
|
248 |
|
|
function feeds_ui_delete_form_submit($form, &$form_state) {
|
249 |
|
|
$form_state['redirect'] = 'admin/structure/feeds';
|
250 |
|
|
|
251 |
|
|
// Remove importer.
|
252 |
|
|
feeds_importer($form['#importer'])->delete();
|
253 |
|
|
|
254 |
|
|
// Clear cache, deleting a configuration may have an affect on menu tree.
|
255 |
|
|
feeds_cache_clear();
|
256 |
|
|
}
|
257 |
|
|
|
258 |
|
|
/**
|
259 |
|
|
* Export a feed configuration.
|
260 |
|
|
*/
|
261 |
|
|
function feeds_ui_export_form($form, &$form_state, $importer) {
|
262 |
|
|
$code = feeds_export($importer->id);
|
263 |
|
|
|
264 |
|
|
$form['export'] = array(
|
265 |
|
|
'#title' => t('Export feed configuration'),
|
266 |
|
|
'#type' => 'textarea',
|
267 |
|
|
'#value' => $code,
|
268 |
|
|
'#rows' => substr_count($code, "\n"),
|
269 |
|
|
);
|
270 |
|
|
return $form;
|
271 |
|
|
}
|
272 |
|
|
|
273 |
|
|
/**
|
274 |
|
|
* Edit feed configuration.
|
275 |
|
|
*/
|
276 |
41cc1b08
|
Assos Assos
|
function feeds_ui_edit_page(FeedsImporter $importer, $active = 'help', $plugin_key = '') {
|
277 |
85ad3d82
|
Assos Assos
|
// Get plugins and configuration.
|
278 |
|
|
$plugins = FeedsPlugin::all();
|
279 |
41cc1b08
|
Assos Assos
|
|
280 |
85ad3d82
|
Assos Assos
|
$config = $importer->config;
|
281 |
|
|
// Base path for changing the active container.
|
282 |
|
|
$path = 'admin/structure/feeds/' . $importer->id;
|
283 |
|
|
|
284 |
|
|
$active_container = array(
|
285 |
|
|
'class' => array('active-container'),
|
286 |
|
|
'actions' => array(l(t('Help'), $path)),
|
287 |
|
|
);
|
288 |
|
|
switch ($active) {
|
289 |
|
|
case 'help':
|
290 |
|
|
$active_container['title'] = t('Getting started');
|
291 |
|
|
$active_container['body'] = '<div class="help feeds-admin-ui">' . feeds_ui_edit_help() . '</div>';
|
292 |
|
|
unset($active_container['actions']);
|
293 |
|
|
break;
|
294 |
41cc1b08
|
Assos Assos
|
|
295 |
85ad3d82
|
Assos Assos
|
case 'fetcher':
|
296 |
|
|
case 'parser':
|
297 |
|
|
case 'processor':
|
298 |
|
|
$active_container['title'] = t('Select a !plugin_type', array('!plugin_type' => $active));
|
299 |
|
|
$active_container['body'] = drupal_get_form('feeds_ui_plugin_form', $importer, $active);
|
300 |
|
|
break;
|
301 |
41cc1b08
|
Assos Assos
|
|
302 |
85ad3d82
|
Assos Assos
|
case 'settings':
|
303 |
|
|
drupal_add_js(drupal_get_path('module', 'ctools') . '/js/dependent.js');
|
304 |
|
|
ctools_include('dependent');
|
305 |
|
|
if (empty($plugin_key)) {
|
306 |
|
|
$active_container['title'] = t('Basic settings');
|
307 |
|
|
$active_container['body'] = feeds_get_form($importer, 'configForm');
|
308 |
|
|
}
|
309 |
|
|
// feeds_plugin() returns a correct result because feed has been
|
310 |
|
|
// instantiated previously.
|
311 |
|
|
elseif (in_array($plugin_key, array_keys($plugins)) && $plugin = feeds_plugin($plugin_key, $importer->id)) {
|
312 |
|
|
$active_container['title'] = t('Settings for !plugin', array('!plugin' => $plugins[$plugin_key]['name']));
|
313 |
|
|
$active_container['body'] = feeds_get_form($plugin, 'configForm');
|
314 |
|
|
}
|
315 |
|
|
break;
|
316 |
41cc1b08
|
Assos Assos
|
|
317 |
85ad3d82
|
Assos Assos
|
case 'mapping':
|
318 |
41cc1b08
|
Assos Assos
|
$processor_name = isset($plugins[$config['processor']['plugin_key']]['name']) ? $plugins[$config['processor']['plugin_key']]['name'] : $plugins['FeedsMissingPlugin']['name'];
|
319 |
|
|
$active_container['title'] = t('Mapping for @processor', array('@processor' => $processor_name));
|
320 |
85ad3d82
|
Assos Assos
|
$active_container['body'] = drupal_get_form('feeds_ui_mapping_form', $importer);
|
321 |
|
|
break;
|
322 |
|
|
}
|
323 |
|
|
|
324 |
|
|
// Build config info.
|
325 |
|
|
$config_info = $info = array();
|
326 |
|
|
$info['class'] = array('config-set');
|
327 |
|
|
|
328 |
|
|
// Basic information.
|
329 |
|
|
$items = array();
|
330 |
|
|
$items[] = t('Attached to: @type', array('@type' => $importer->config['content_type'] ? node_type_get_name($importer->config['content_type']) : t('[none]')));
|
331 |
|
|
if ($importer->config['import_period'] == FEEDS_SCHEDULE_NEVER) {
|
332 |
|
|
$import_period = t('off');
|
333 |
|
|
}
|
334 |
|
|
elseif ($importer->config['import_period'] == 0) {
|
335 |
|
|
$import_period = t('as often as possible');
|
336 |
|
|
}
|
337 |
|
|
else {
|
338 |
|
|
$import_period = t('every !interval', array('!interval' => format_interval($importer->config['import_period'])));
|
339 |
|
|
}
|
340 |
|
|
$items[] = t('Periodic import: !import_period', array('!import_period' => $import_period));
|
341 |
|
|
$items[] = $importer->config['import_on_create'] ? t('Import on submission') : t('Do not import on submission');
|
342 |
|
|
|
343 |
|
|
$info['title'] = t('Basic settings');
|
344 |
|
|
$info['body'] = array(
|
345 |
|
|
array(
|
346 |
|
|
'body' => theme('item_list', array('items' => $items)),
|
347 |
|
|
'actions' => array(l(t('Settings'), $path . '/settings')),
|
348 |
|
|
),
|
349 |
|
|
);
|
350 |
|
|
$config_info[] = $info;
|
351 |
|
|
|
352 |
|
|
// Fetcher.
|
353 |
41cc1b08
|
Assos Assos
|
$fetcher = isset($plugins[$config['fetcher']['plugin_key']]) ? $plugins[$config['fetcher']['plugin_key']] : $plugins['FeedsMissingPlugin'];
|
354 |
85ad3d82
|
Assos Assos
|
$actions = array();
|
355 |
41cc1b08
|
Assos Assos
|
if ($importer->fetcher->hasConfigForm()) {
|
356 |
85ad3d82
|
Assos Assos
|
$actions = array(l(t('Settings'), $path . '/settings/' . $config['fetcher']['plugin_key']));
|
357 |
|
|
}
|
358 |
|
|
$info['title'] = t('Fetcher');
|
359 |
|
|
$info['body'] = array(
|
360 |
|
|
array(
|
361 |
|
|
'title' => $fetcher['name'],
|
362 |
|
|
'body' => $fetcher['description'],
|
363 |
|
|
'actions' => $actions,
|
364 |
|
|
),
|
365 |
|
|
);
|
366 |
|
|
$info['actions'] = array(l(t('Change'), $path . '/fetcher'));
|
367 |
|
|
$config_info[] = $info;
|
368 |
|
|
|
369 |
|
|
// Parser.
|
370 |
41cc1b08
|
Assos Assos
|
$parser = isset($plugins[$config['parser']['plugin_key']]) ? $plugins[$config['parser']['plugin_key']] : $plugins['FeedsMissingPlugin'];
|
371 |
85ad3d82
|
Assos Assos
|
$actions = array();
|
372 |
41cc1b08
|
Assos Assos
|
if ($importer->parser->hasConfigForm()) {
|
373 |
85ad3d82
|
Assos Assos
|
$actions = array(l(t('Settings'), $path . '/settings/' . $config['parser']['plugin_key']));
|
374 |
|
|
}
|
375 |
|
|
$info['title'] = t('Parser');
|
376 |
|
|
$info['body'] = array(
|
377 |
|
|
array(
|
378 |
|
|
'title' => $parser['name'],
|
379 |
|
|
'body' => $parser['description'],
|
380 |
|
|
'actions' => $actions,
|
381 |
|
|
)
|
382 |
|
|
);
|
383 |
|
|
$info['actions'] = array(l(t('Change'), $path . '/parser'));
|
384 |
|
|
$config_info[] = $info;
|
385 |
|
|
|
386 |
|
|
// Processor.
|
387 |
41cc1b08
|
Assos Assos
|
$processor = isset($plugins[$config['processor']['plugin_key']]) ? $plugins[$config['processor']['plugin_key']] : $plugins['FeedsMissingPlugin'];
|
388 |
85ad3d82
|
Assos Assos
|
$actions = array();
|
389 |
41cc1b08
|
Assos Assos
|
if ($importer->processor->hasConfigForm()) {
|
390 |
85ad3d82
|
Assos Assos
|
$actions[] = l(t('Settings'), $path . '/settings/' . $config['processor']['plugin_key']);
|
391 |
|
|
}
|
392 |
|
|
$actions[] = l(t('Mapping'), $path . '/mapping');
|
393 |
|
|
$info['title'] = t('Processor');
|
394 |
|
|
$info['body'] = array(
|
395 |
|
|
array(
|
396 |
|
|
'title' => $processor['name'],
|
397 |
|
|
'body' => $processor['description'],
|
398 |
|
|
'actions' => $actions,
|
399 |
|
|
)
|
400 |
|
|
);
|
401 |
|
|
$info['actions'] = array(l(t('Change'), $path . '/processor'));
|
402 |
|
|
$config_info[] = $info;
|
403 |
|
|
|
404 |
|
|
return theme('feeds_ui_edit_page', array(
|
405 |
|
|
'info' => $config_info,
|
406 |
|
|
'active' => $active_container,
|
407 |
|
|
));
|
408 |
|
|
}
|
409 |
|
|
|
410 |
|
|
/**
|
411 |
|
|
* Build a form of plugins to pick from.
|
412 |
|
|
*
|
413 |
|
|
* @param $form_state
|
414 |
|
|
* Form API form state array.
|
415 |
|
|
* @param $importer
|
416 |
|
|
* FeedsImporter object.
|
417 |
|
|
* @param $type
|
418 |
|
|
* Plugin type. One of 'fetcher', 'parser', 'processor'.
|
419 |
|
|
*
|
420 |
|
|
* @return
|
421 |
|
|
* A Form API form definition.
|
422 |
|
|
*/
|
423 |
|
|
function feeds_ui_plugin_form($form, &$form_state, $importer, $type) {
|
424 |
|
|
$plugins = FeedsPlugin::byType($type);
|
425 |
|
|
|
426 |
|
|
$form['#importer'] = $importer->id;
|
427 |
|
|
$form['#plugin_type'] = $type;
|
428 |
|
|
|
429 |
|
|
$importer_key = $importer->config[$type]['plugin_key'];
|
430 |
|
|
|
431 |
|
|
foreach ($plugins as $key => $plugin) {
|
432 |
|
|
|
433 |
|
|
$form['plugin_key'][$key] = array(
|
434 |
|
|
'#type' => 'radio',
|
435 |
|
|
'#parents' => array('plugin_key'),
|
436 |
|
|
'#title' => check_plain($plugin['name']),
|
437 |
|
|
'#description' => filter_xss(isset($plugin['help']) ? $plugin['help'] : $plugin['description']),
|
438 |
|
|
'#return_value' => $key,
|
439 |
|
|
'#default_value' => ($key == $importer_key) ? $key : '',
|
440 |
|
|
);
|
441 |
|
|
}
|
442 |
|
|
$form['submit'] = array(
|
443 |
|
|
'#type' => 'submit',
|
444 |
|
|
'#value' => t('Save'),
|
445 |
|
|
);
|
446 |
|
|
return $form;
|
447 |
|
|
}
|
448 |
|
|
|
449 |
|
|
/**
|
450 |
|
|
* Submit handler for feeds_ui_plugin_form().
|
451 |
|
|
*/
|
452 |
|
|
function feeds_ui_plugin_form_submit($form, &$form_state) {
|
453 |
|
|
// Set the plugin and save feed.
|
454 |
|
|
$importer = feeds_importer($form['#importer']);
|
455 |
|
|
$importer->setPlugin($form_state['values']['plugin_key']);
|
456 |
|
|
$importer->save();
|
457 |
|
|
drupal_set_message(t('Changed @type plugin.', array('@type' => $form['#plugin_type'])));
|
458 |
|
|
}
|
459 |
|
|
|
460 |
|
|
/**
|
461 |
|
|
* Theme feeds_ui_plugin_form().
|
462 |
|
|
*/
|
463 |
|
|
function theme_feeds_ui_plugin_form($variables) {
|
464 |
|
|
$form = $variables['form'];
|
465 |
|
|
$output = '';
|
466 |
|
|
|
467 |
|
|
foreach (element_children($form['plugin_key']) as $key) {
|
468 |
|
|
|
469 |
|
|
// Assemble container, render form elements.
|
470 |
|
|
$container = array(
|
471 |
|
|
'title' => $form['plugin_key'][$key]['#title'],
|
472 |
|
|
'body' => isset($form['plugin_key'][$key]['#description']) ? $form['plugin_key'][$key]['#description'] : '',
|
473 |
|
|
);
|
474 |
|
|
$form['plugin_key'][$key]['#title'] = t('Select');
|
475 |
|
|
$form['plugin_key'][$key]['#attributes']['class'] = array('feeds-ui-radio-link');
|
476 |
|
|
unset($form['plugin_key'][$key]['#description']);
|
477 |
|
|
$container['actions'] = array(drupal_render($form['plugin_key'][$key]));
|
478 |
|
|
|
479 |
|
|
$output .= theme('feeds_ui_container', array('container' => $container));
|
480 |
|
|
}
|
481 |
|
|
|
482 |
|
|
$output .= drupal_render_children($form);
|
483 |
|
|
return $output;
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
/**
|
487 |
|
|
* Edit mapping.
|
488 |
|
|
*
|
489 |
|
|
* @todo Completely merge this into config form handling. This is just a
|
490 |
|
|
* shared form of configuration, most of the common functionality can live in
|
491 |
|
|
* FeedsProcessor, a flag can tell whether mapping is supported or not.
|
492 |
|
|
*/
|
493 |
|
|
function feeds_ui_mapping_form($form, &$form_state, $importer) {
|
494 |
|
|
$form['#importer'] = $importer->id;
|
495 |
|
|
$form['#mappings'] = $mappings = $importer->processor->getMappings();
|
496 |
|
|
$form['help']['#markup'] = feeds_ui_mapping_help();
|
497 |
|
|
$form['#prefix'] = '<div id="feeds-ui-mapping-form-wrapper">';
|
498 |
|
|
$form['#suffix'] = '</div>';
|
499 |
|
|
|
500 |
41cc1b08
|
Assos Assos
|
// Show message when target configuration gets changed.
|
501 |
|
|
if (!empty($form_state['mapping_settings'])) {
|
502 |
|
|
$form['#mapping_settings'] = $form_state['mapping_settings'];
|
503 |
|
|
$form['changed'] = array(
|
504 |
|
|
'#theme_wrappers' => array('container'),
|
505 |
|
|
'#attributes' => array('class' => array('messages', 'warning')),
|
506 |
|
|
'#markup' => t('* Changes made to target configuration are stored temporarily. Click Save to make your changes permanent.'),
|
507 |
|
|
);
|
508 |
|
|
}
|
509 |
|
|
|
510 |
85ad3d82
|
Assos Assos
|
// Get mapping sources from parsers and targets from processor, format them
|
511 |
|
|
// for output.
|
512 |
|
|
// Some parsers do not define mapping sources but let them define on the fly.
|
513 |
|
|
if ($sources = $importer->parser->getMappingSources()) {
|
514 |
|
|
$source_options = _feeds_ui_format_options($sources);
|
515 |
|
|
foreach ($sources as $k => $source) {
|
516 |
|
|
$legend['sources'][$k]['name']['#markup'] = empty($source['name']) ? $k : $source['name'];
|
517 |
|
|
$legend['sources'][$k]['description']['#markup'] = empty($source['description']) ? '' : $source['description'];
|
518 |
|
|
}
|
519 |
|
|
}
|
520 |
|
|
else {
|
521 |
|
|
$legend['sources']['#markup'] = t('This parser supports free source definitions. Enter the name of the source field in lower case into the Source text field above.');
|
522 |
|
|
}
|
523 |
|
|
$targets = $importer->processor->getMappingTargets();
|
524 |
|
|
$target_options = _feeds_ui_format_options($targets);
|
525 |
|
|
$legend['targets'] = array();
|
526 |
|
|
foreach ($targets as $k => $target) {
|
527 |
|
|
$legend['targets'][$k]['name']['#markup'] = empty($target['name']) ? $k : $target['name'];
|
528 |
|
|
$legend['targets'][$k]['description']['#markup'] = empty($target['description']) ? '' : $target['description'];
|
529 |
|
|
}
|
530 |
|
|
|
531 |
|
|
// Legend explaining source and target elements.
|
532 |
|
|
$form['legendset'] = array(
|
533 |
|
|
'#type' => 'fieldset',
|
534 |
|
|
'#title' => t('Legend'),
|
535 |
|
|
'#collapsible' => TRUE,
|
536 |
|
|
'#collapsed' => TRUE,
|
537 |
|
|
'#tree' => TRUE,
|
538 |
|
|
);
|
539 |
|
|
$form['legendset']['legend'] = $legend;
|
540 |
|
|
|
541 |
|
|
// Add config forms and remove flags to mappings.
|
542 |
|
|
$form['config'] = $form['remove_flags'] = $form['mapping_weight'] = array(
|
543 |
|
|
'#tree' => TRUE,
|
544 |
|
|
);
|
545 |
|
|
if (is_array($mappings)) {
|
546 |
|
|
|
547 |
|
|
$delta = count($mappings) + 2;
|
548 |
|
|
|
549 |
|
|
foreach ($mappings as $i => $mapping) {
|
550 |
|
|
if (isset($targets[$mapping['target']])) {
|
551 |
|
|
$form['config'][$i] = feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $targets[$mapping['target']]);
|
552 |
|
|
}
|
553 |
|
|
|
554 |
|
|
$form['remove_flags'][$i] = array(
|
555 |
|
|
'#type' => 'checkbox',
|
556 |
|
|
'#title' => t('Remove'),
|
557 |
|
|
'#prefix' => '<div class="feeds-ui-checkbox-link">',
|
558 |
|
|
'#suffix' => '</div>',
|
559 |
|
|
);
|
560 |
|
|
|
561 |
|
|
$form['mapping_weight'][$i] = array(
|
562 |
|
|
'#type' => 'weight',
|
563 |
|
|
'#title' => '',
|
564 |
|
|
'#default_value' => $i,
|
565 |
|
|
'#delta' => $delta,
|
566 |
|
|
'#attributes' => array(
|
567 |
|
|
'class' => array(
|
568 |
|
|
'feeds-ui-mapping-weight'
|
569 |
|
|
),
|
570 |
|
|
),
|
571 |
|
|
);
|
572 |
|
|
}
|
573 |
|
|
}
|
574 |
|
|
|
575 |
|
|
if (isset($source_options)) {
|
576 |
|
|
$form['source'] = array(
|
577 |
|
|
'#type' => 'select',
|
578 |
|
|
'#title' => t('Source'),
|
579 |
|
|
'#title_display' => 'invisible',
|
580 |
|
|
'#options' => $source_options,
|
581 |
|
|
'#empty_option' => t('- Select a source -'),
|
582 |
|
|
'#description' => t('An element from the feed.'),
|
583 |
|
|
);
|
584 |
|
|
}
|
585 |
|
|
else {
|
586 |
|
|
$form['source'] = array(
|
587 |
|
|
'#type' => 'textfield',
|
588 |
|
|
'#title' => t('Source'),
|
589 |
|
|
'#title_display' => 'invisible',
|
590 |
|
|
'#size' => 20,
|
591 |
|
|
'#default_value' => '',
|
592 |
|
|
'#description' => t('The name of source field.'),
|
593 |
|
|
);
|
594 |
|
|
}
|
595 |
|
|
$form['target'] = array(
|
596 |
|
|
'#type' => 'select',
|
597 |
|
|
'#title' => t('Target'),
|
598 |
|
|
'#title_display' => 'invisible',
|
599 |
|
|
'#options' => $target_options,
|
600 |
|
|
'#empty_option' => t('- Select a target -'),
|
601 |
|
|
'#description' => t('The field that stores the data.'),
|
602 |
|
|
);
|
603 |
|
|
|
604 |
|
|
$form['actions'] = array('#type' => 'actions');
|
605 |
|
|
$form['actions']['save'] = array(
|
606 |
|
|
'#type' => 'submit',
|
607 |
|
|
'#value' => t('Save'),
|
608 |
|
|
);
|
609 |
|
|
return $form;
|
610 |
|
|
}
|
611 |
|
|
|
612 |
|
|
/**
|
613 |
|
|
* Per mapper configuration form that is a part of feeds_ui_mapping_form().
|
614 |
|
|
*/
|
615 |
|
|
function feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $target) {
|
616 |
|
|
$form_state += array(
|
617 |
|
|
'mapping_settings_edit' => NULL,
|
618 |
|
|
'mapping_settings' => array(),
|
619 |
|
|
);
|
620 |
|
|
|
621 |
|
|
$base_button = array(
|
622 |
|
|
'#submit' => array('feeds_ui_mapping_form_multistep_submit'),
|
623 |
|
|
'#ajax' => array(
|
624 |
|
|
'callback' => 'feeds_ui_mapping_settings_form_callback',
|
625 |
|
|
'wrapper' => 'feeds-ui-mapping-form-wrapper',
|
626 |
|
|
'effect' => 'fade',
|
627 |
|
|
'progress' => 'none',
|
628 |
|
|
),
|
629 |
|
|
'#i' => $i,
|
630 |
|
|
);
|
631 |
|
|
|
632 |
|
|
if (isset($form_state['mapping_settings'][$i])) {
|
633 |
|
|
$mapping = $form_state['mapping_settings'][$i] + $mapping;
|
634 |
|
|
}
|
635 |
|
|
|
636 |
|
|
if ($form_state['mapping_settings_edit'] === $i) {
|
637 |
41cc1b08
|
Assos Assos
|
$settings_form = array();
|
638 |
|
|
|
639 |
|
|
foreach ($target['form_callbacks'] as $callback) {
|
640 |
|
|
$settings_form += call_user_func($callback, $mapping, $target, $form, $form_state);
|
641 |
85ad3d82
|
Assos Assos
|
}
|
642 |
|
|
|
643 |
|
|
// Merge in the optional unique form.
|
644 |
|
|
$settings_form += feeds_ui_mapping_settings_optional_unique_form($mapping, $target, $form, $form_state);
|
645 |
|
|
|
646 |
|
|
return array(
|
647 |
|
|
'#type' => 'container',
|
648 |
|
|
'settings' => $settings_form,
|
649 |
|
|
'save_settings' => $base_button + array(
|
650 |
|
|
'#type' => 'submit',
|
651 |
|
|
'#name' => 'mapping_settings_update_' . $i,
|
652 |
|
|
'#value' => t('Update'),
|
653 |
|
|
'#op' => 'update',
|
654 |
|
|
),
|
655 |
|
|
'cancel_settings' => $base_button + array(
|
656 |
|
|
'#type' => 'submit',
|
657 |
|
|
'#name' => 'mapping_settings_cancel_' . $i,
|
658 |
|
|
'#value' => t('Cancel'),
|
659 |
|
|
'#op' => 'cancel',
|
660 |
|
|
),
|
661 |
|
|
);
|
662 |
|
|
}
|
663 |
|
|
else {
|
664 |
|
|
// Build the summary.
|
665 |
41cc1b08
|
Assos Assos
|
$summary = array();
|
666 |
|
|
|
667 |
|
|
foreach ($target['summary_callbacks'] as $callback) {
|
668 |
|
|
$summary[] = call_user_func($callback, $mapping, $target, $form, $form_state);
|
669 |
85ad3d82
|
Assos Assos
|
}
|
670 |
|
|
|
671 |
41cc1b08
|
Assos Assos
|
// Filter out empty summary values.
|
672 |
|
|
$summary = implode('<br />', array_filter($summary));
|
673 |
|
|
|
674 |
85ad3d82
|
Assos Assos
|
// Append the optional unique summary.
|
675 |
|
|
if ($optional_unique_summary = feeds_ui_mapping_settings_optional_unique_summary($mapping, $target, $form, $form_state)) {
|
676 |
|
|
$summary .= ' ' . $optional_unique_summary;
|
677 |
|
|
}
|
678 |
|
|
|
679 |
|
|
if ($summary) {
|
680 |
|
|
return array(
|
681 |
|
|
'summary' => array(
|
682 |
|
|
'#prefix' => '<div>',
|
683 |
|
|
'#markup' => $summary,
|
684 |
|
|
'#suffix' => '</div>',
|
685 |
|
|
),
|
686 |
|
|
'edit_settings' => $base_button + array(
|
687 |
|
|
'#type' => 'image_button',
|
688 |
|
|
'#name' => 'mapping_settings_edit_' . $i,
|
689 |
|
|
'#src' => 'misc/configure.png',
|
690 |
|
|
'#attributes' => array('alt' => t('Edit')),
|
691 |
|
|
'#op' => 'edit',
|
692 |
|
|
),
|
693 |
|
|
);
|
694 |
|
|
}
|
695 |
|
|
}
|
696 |
41cc1b08
|
Assos Assos
|
return array();
|
697 |
85ad3d82
|
Assos Assos
|
}
|
698 |
|
|
|
699 |
|
|
/**
|
700 |
|
|
* Submit callback for a per mapper configuration form. Switches between edit
|
701 |
|
|
* and summary mode.
|
702 |
|
|
*/
|
703 |
|
|
function feeds_ui_mapping_form_multistep_submit($form, &$form_state) {
|
704 |
|
|
$trigger = $form_state['triggering_element'];
|
705 |
|
|
|
706 |
|
|
switch ($trigger['#op']) {
|
707 |
|
|
case 'edit':
|
708 |
|
|
$form_state['mapping_settings_edit'] = $trigger['#i'];
|
709 |
|
|
break;
|
710 |
|
|
|
711 |
|
|
case 'update':
|
712 |
|
|
$values = $form_state['values']['config'][$trigger['#i']]['settings'];
|
713 |
|
|
$form_state['mapping_settings'][$trigger['#i']] = $values;
|
714 |
|
|
unset($form_state['mapping_settings_edit']);
|
715 |
|
|
break;
|
716 |
|
|
|
717 |
|
|
case 'cancel':
|
718 |
|
|
unset($form_state['mapping_settings_edit']);
|
719 |
|
|
break;
|
720 |
|
|
}
|
721 |
|
|
|
722 |
|
|
$form_state['rebuild'] = TRUE;
|
723 |
|
|
}
|
724 |
|
|
|
725 |
|
|
/**
|
726 |
|
|
* AJAX callback that returns the whole feeds_ui_mapping_form().
|
727 |
|
|
*/
|
728 |
|
|
function feeds_ui_mapping_settings_form_callback($form, $form_state) {
|
729 |
|
|
return $form;
|
730 |
|
|
}
|
731 |
|
|
|
732 |
|
|
/**
|
733 |
|
|
* Validation handler for feeds_ui_mapping_form().
|
734 |
|
|
*/
|
735 |
|
|
function feeds_ui_mapping_form_validate($form, &$form_state) {
|
736 |
41cc1b08
|
Assos Assos
|
if (!strlen($form_state['values']['source']) xor !strlen($form_state['values']['target'])) {
|
737 |
85ad3d82
|
Assos Assos
|
|
738 |
|
|
// Check triggering_element here so we can react differently for ajax
|
739 |
|
|
// submissions.
|
740 |
|
|
switch ($form_state['triggering_element']['#name']) {
|
741 |
|
|
|
742 |
|
|
// Regular form submission.
|
743 |
|
|
case 'op':
|
744 |
41cc1b08
|
Assos Assos
|
if (!strlen($form_state['values']['source'])) {
|
745 |
85ad3d82
|
Assos Assos
|
form_error($form['source'], t('You must select a mapping source.'));
|
746 |
|
|
}
|
747 |
|
|
else {
|
748 |
|
|
form_error($form['target'], t('You must select a mapping target.'));
|
749 |
|
|
}
|
750 |
|
|
break;
|
751 |
|
|
|
752 |
|
|
// Be more relaxed on ajax submission.
|
753 |
|
|
default:
|
754 |
|
|
form_set_value($form['source'], '', $form_state);
|
755 |
|
|
form_set_value($form['target'], '', $form_state);
|
756 |
|
|
break;
|
757 |
|
|
}
|
758 |
|
|
}
|
759 |
|
|
}
|
760 |
|
|
|
761 |
|
|
/**
|
762 |
|
|
* Submission handler for feeds_ui_mapping_form().
|
763 |
|
|
*/
|
764 |
|
|
function feeds_ui_mapping_form_submit($form, &$form_state) {
|
765 |
|
|
$importer = feeds_importer($form['#importer']);
|
766 |
|
|
$processor = $importer->processor;
|
767 |
|
|
|
768 |
|
|
$form_state += array(
|
769 |
|
|
'mapping_settings' => array(),
|
770 |
|
|
'mapping_settings_edit' => NULL,
|
771 |
|
|
);
|
772 |
|
|
|
773 |
|
|
// If an item is in edit mode, prepare it for saving.
|
774 |
|
|
if ($form_state['mapping_settings_edit'] !== NULL) {
|
775 |
|
|
$values = $form_state['values']['config'][$form_state['mapping_settings_edit']]['settings'];
|
776 |
|
|
$form_state['mapping_settings'][$form_state['mapping_settings_edit']] = $values;
|
777 |
|
|
}
|
778 |
|
|
|
779 |
|
|
// We may set some settings to mappings that we remove in the subsequent step,
|
780 |
|
|
// that's fine.
|
781 |
|
|
$mappings = $form['#mappings'];
|
782 |
|
|
foreach ($form_state['mapping_settings'] as $k => $v) {
|
783 |
|
|
$mappings[$k] = array(
|
784 |
|
|
'source' => $mappings[$k]['source'],
|
785 |
|
|
'target' => $mappings[$k]['target'],
|
786 |
|
|
) + $v;
|
787 |
|
|
}
|
788 |
|
|
|
789 |
|
|
if (!empty($form_state['values']['remove_flags'])) {
|
790 |
|
|
$remove_flags = array_keys(array_filter($form_state['values']['remove_flags']));
|
791 |
|
|
|
792 |
|
|
foreach ($remove_flags as $k) {
|
793 |
|
|
unset($mappings[$k]);
|
794 |
|
|
unset($form_state['values']['mapping_weight'][$k]);
|
795 |
|
|
drupal_set_message(t('Mapping has been removed.'), 'status', FALSE);
|
796 |
|
|
}
|
797 |
|
|
}
|
798 |
|
|
|
799 |
|
|
// Keep our keys clean.
|
800 |
|
|
$mappings = array_values($mappings);
|
801 |
|
|
|
802 |
|
|
if (!empty($mappings)) {
|
803 |
|
|
array_multisort($form_state['values']['mapping_weight'], $mappings);
|
804 |
|
|
}
|
805 |
|
|
|
806 |
|
|
$processor->addConfig(array('mappings' => $mappings));
|
807 |
|
|
|
808 |
41cc1b08
|
Assos Assos
|
if (strlen($form_state['values']['source']) && strlen($form_state['values']['target'])) {
|
809 |
85ad3d82
|
Assos Assos
|
try {
|
810 |
|
|
$mappings = $processor->getMappings();
|
811 |
|
|
$mappings[] = array(
|
812 |
|
|
'source' => $form_state['values']['source'],
|
813 |
|
|
'target' => $form_state['values']['target'],
|
814 |
|
|
'unique' => FALSE,
|
815 |
|
|
);
|
816 |
|
|
$processor->addConfig(array('mappings' => $mappings));
|
817 |
|
|
drupal_set_message(t('Mapping has been added.'));
|
818 |
|
|
}
|
819 |
|
|
catch (Exception $e) {
|
820 |
|
|
drupal_set_message($e->getMessage(), 'error');
|
821 |
|
|
}
|
822 |
|
|
}
|
823 |
|
|
|
824 |
|
|
$importer->save();
|
825 |
|
|
drupal_set_message(t('Your changes have been saved.'));
|
826 |
|
|
}
|
827 |
|
|
|
828 |
|
|
/**
|
829 |
|
|
* Walk the result of FeedsParser::getMappingSources() or
|
830 |
|
|
* FeedsProcessor::getMappingTargets() and format them into
|
831 |
|
|
* a Form API options array.
|
832 |
|
|
*/
|
833 |
|
|
function _feeds_ui_format_options($options) {
|
834 |
|
|
$result = array();
|
835 |
|
|
foreach ($options as $k => $v) {
|
836 |
|
|
if (is_array($v) && !empty($v['name'])) {
|
837 |
41cc1b08
|
Assos Assos
|
$result[$k] = $v['name'] . ' (' . $k . ')';
|
838 |
85ad3d82
|
Assos Assos
|
}
|
839 |
|
|
elseif (is_array($v)) {
|
840 |
|
|
$result[$k] = $k;
|
841 |
|
|
}
|
842 |
|
|
else {
|
843 |
|
|
$result[$k] = $v;
|
844 |
|
|
}
|
845 |
|
|
}
|
846 |
|
|
asort($result);
|
847 |
|
|
return $result;
|
848 |
|
|
}
|
849 |
|
|
|
850 |
|
|
/**
|
851 |
|
|
* Per mapping settings summary callback. Shows whether a mapping is used as
|
852 |
|
|
* unique or not.
|
853 |
|
|
*/
|
854 |
|
|
function feeds_ui_mapping_settings_optional_unique_summary($mapping, $target, $form, $form_state) {
|
855 |
|
|
if (!empty($target['optional_unique'])) {
|
856 |
|
|
if ($mapping['unique']) {
|
857 |
|
|
return t('Used as <strong>unique</strong>.');
|
858 |
|
|
}
|
859 |
|
|
else {
|
860 |
|
|
return t('Not used as unique.');
|
861 |
|
|
}
|
862 |
|
|
}
|
863 |
|
|
}
|
864 |
|
|
|
865 |
|
|
/**
|
866 |
|
|
* Per mapping settings form callback. Lets the user choose if a target is as
|
867 |
|
|
* unique or not.
|
868 |
|
|
*/
|
869 |
|
|
function feeds_ui_mapping_settings_optional_unique_form($mapping, $target, $form, $form_state) {
|
870 |
|
|
$settings_form = array();
|
871 |
|
|
|
872 |
|
|
if (!empty($target['optional_unique'])) {
|
873 |
|
|
$settings_form['unique'] = array(
|
874 |
|
|
'#type' => 'checkbox',
|
875 |
|
|
'#title' => t('Unique'),
|
876 |
|
|
'#default_value' => !empty($mapping['unique']),
|
877 |
|
|
);
|
878 |
|
|
}
|
879 |
|
|
|
880 |
|
|
return $settings_form;
|
881 |
|
|
}
|
882 |
|
|
|
883 |
|
|
/**
|
884 |
|
|
* Theme feeds_ui_overview_form().
|
885 |
|
|
*/
|
886 |
|
|
function theme_feeds_ui_overview_form($variables) {
|
887 |
|
|
$form = $variables['form'];
|
888 |
|
|
drupal_add_css(drupal_get_path('module', 'feeds_ui') . '/feeds_ui.css');
|
889 |
|
|
|
890 |
|
|
// Iterate through all importers and build a table.
|
891 |
|
|
$rows = array();
|
892 |
|
|
foreach (array('enabled', 'disabled') as $type) {
|
893 |
|
|
if (isset($form[$type])) {
|
894 |
|
|
foreach (element_children($form[$type]) as $id) {
|
895 |
|
|
$row = array();
|
896 |
|
|
foreach (element_children($form[$type][$id]) as $col) {
|
897 |
|
|
$row[$col] = array(
|
898 |
|
|
'data' => drupal_render($form[$type][$id][$col]),
|
899 |
|
|
'class' => array($type),
|
900 |
|
|
);
|
901 |
|
|
}
|
902 |
|
|
$rows[] = array(
|
903 |
|
|
'data' => $row,
|
904 |
|
|
'class' => array($type),
|
905 |
|
|
);
|
906 |
|
|
}
|
907 |
|
|
}
|
908 |
|
|
}
|
909 |
|
|
|
910 |
|
|
$output = theme('table', array(
|
911 |
|
|
'header' => $form['#header'],
|
912 |
|
|
'rows' => $rows,
|
913 |
|
|
'attributes' => array('class' => array('feeds-admin-importers')),
|
914 |
|
|
'empty' => t('No importers available.'),
|
915 |
|
|
));
|
916 |
|
|
|
917 |
|
|
if (!empty($rows)) {
|
918 |
|
|
$output .= drupal_render_children($form);
|
919 |
|
|
}
|
920 |
|
|
|
921 |
|
|
return $output;
|
922 |
|
|
}
|
923 |
|
|
|
924 |
|
|
/**
|
925 |
|
|
* Theme feeds_ui_edit_page().
|
926 |
|
|
*/
|
927 |
|
|
function theme_feeds_ui_edit_page($variables) {
|
928 |
|
|
$config_info = $variables['info'];
|
929 |
|
|
$active_container = $variables['active'];
|
930 |
|
|
drupal_add_css(drupal_get_path('module', 'feeds_ui') . '/feeds_ui.css');
|
931 |
|
|
|
932 |
|
|
// Outer wrapper.
|
933 |
|
|
$output = '<div class="feeds-settings clear-block">';
|
934 |
|
|
|
935 |
|
|
// Build left bar.
|
936 |
|
|
$output .= '<div class="left-bar">';
|
937 |
|
|
foreach ($config_info as $info) {
|
938 |
|
|
$output .= theme('feeds_ui_container', array('container' => $info));
|
939 |
|
|
}
|
940 |
|
|
$output .= '</div>';
|
941 |
|
|
|
942 |
|
|
// Build configuration space.
|
943 |
|
|
$output .= '<div class="configuration">';
|
944 |
|
|
$output .= '<div class="configuration-squeeze">';
|
945 |
|
|
$output .= theme('feeds_ui_container', array('container' => $active_container));
|
946 |
|
|
$output .= '</div>';
|
947 |
|
|
$output .= '</div>';
|
948 |
|
|
|
949 |
|
|
$output .= '</div>'; // ''<div class="feeds-settings">';
|
950 |
|
|
|
951 |
|
|
return $output;
|
952 |
|
|
}
|
953 |
|
|
|
954 |
|
|
/**
|
955 |
|
|
* Render a simple container. A container can have a title, a description and
|
956 |
|
|
* one or more actions. Recursive.
|
957 |
|
|
*
|
958 |
|
|
* @todo Replace with theme_fieldset or a wrapper to theme_fieldset?
|
959 |
|
|
*
|
960 |
|
|
* @param $variables
|
961 |
|
|
* An array containing an array at 'container'.
|
962 |
|
|
* A 'container' array may contain one or more of the following keys:
|
963 |
|
|
* array(
|
964 |
|
|
* 'title' => 'the title',
|
965 |
|
|
* 'body' => 'the body of the container, may also be an array of more
|
966 |
|
|
* containers or a renderable array.',
|
967 |
|
|
* 'class' => array('the class of the container.'),
|
968 |
|
|
* 'id' => 'the id of the container',
|
969 |
|
|
* );
|
970 |
|
|
*/
|
971 |
|
|
function theme_feeds_ui_container($variables) {
|
972 |
|
|
$container = $variables['container'];
|
973 |
|
|
|
974 |
|
|
$class = array_merge(array('feeds-container'), empty($container['class']) ? array('plain') : $container['class']);
|
975 |
|
|
$id = empty($container['id']) ? '': ' id="' . $container['id'] . '"';
|
976 |
|
|
$output = '<div class="' . implode(' ', $class) . '"' . $id . '>';
|
977 |
|
|
|
978 |
|
|
if (isset($container['actions']) && count($container['actions'])) {
|
979 |
|
|
$output .= '<ul class="container-actions">';
|
980 |
|
|
foreach ($container['actions'] as $action) {
|
981 |
|
|
$output .= '<li>' . $action . '</li>';
|
982 |
|
|
}
|
983 |
|
|
$output .= '</ul>';
|
984 |
|
|
}
|
985 |
|
|
|
986 |
|
|
if (!empty($container['title'])) {
|
987 |
|
|
$output .= '<h4 class="feeds-container-title">';
|
988 |
|
|
$output .= $container['title'];
|
989 |
|
|
$output .= '</h4>';
|
990 |
|
|
}
|
991 |
|
|
|
992 |
|
|
if (!empty($container['body'])) {
|
993 |
|
|
$output .= '<div class="feeds-container-body">';
|
994 |
|
|
if (is_array($container['body'])) {
|
995 |
|
|
if (isset($container['body']['#type'])) {
|
996 |
|
|
$output .= drupal_render($container['body']);
|
997 |
|
|
}
|
998 |
|
|
else {
|
999 |
|
|
foreach ($container['body'] as $c) {
|
1000 |
|
|
$output .= theme('feeds_ui_container', array('container' => $c));
|
1001 |
|
|
}
|
1002 |
|
|
}
|
1003 |
|
|
}
|
1004 |
|
|
else {
|
1005 |
|
|
$output .= $container['body'];
|
1006 |
|
|
}
|
1007 |
|
|
$output .= '</div>';
|
1008 |
|
|
}
|
1009 |
|
|
|
1010 |
|
|
$output .= '</div>';
|
1011 |
|
|
return $output;
|
1012 |
|
|
}
|
1013 |
|
|
|
1014 |
|
|
/**
|
1015 |
|
|
* Theme function for feeds_ui_mapping_form().
|
1016 |
|
|
*/
|
1017 |
|
|
function theme_feeds_ui_mapping_form($variables) {
|
1018 |
|
|
$form = $variables['form'];
|
1019 |
|
|
|
1020 |
|
|
// Build the actual mapping table.
|
1021 |
|
|
$header = array(
|
1022 |
|
|
t('Source'),
|
1023 |
|
|
t('Target'),
|
1024 |
|
|
t('Target configuration'),
|
1025 |
|
|
' ',
|
1026 |
|
|
t('Weight'),
|
1027 |
|
|
);
|
1028 |
|
|
$rows = array();
|
1029 |
|
|
if (is_array($form['#mappings'])) {
|
1030 |
|
|
foreach ($form['#mappings'] as $i => $mapping) {
|
1031 |
|
|
// Some parsers do not define source options.
|
1032 |
|
|
$source = isset($form['source']['#options'][$mapping['source']]) ? $form['source']['#options'][$mapping['source']] : $mapping['source'];
|
1033 |
|
|
$target = isset($form['target']['#options'][$mapping['target']]) ? check_plain($form['target']['#options'][$mapping['target']]) : '<em>' . t('Missing') . '</em>';
|
1034 |
41cc1b08
|
Assos Assos
|
// Add indicator to target if target configuration changed.
|
1035 |
|
|
if (isset($form['#mapping_settings'][$i])) {
|
1036 |
|
|
$target .= '<span class="warning">*</span>';
|
1037 |
|
|
}
|
1038 |
85ad3d82
|
Assos Assos
|
$rows[] = array(
|
1039 |
|
|
'data' => array(
|
1040 |
|
|
check_plain($source),
|
1041 |
|
|
$target,
|
1042 |
|
|
drupal_render($form['config'][$i]),
|
1043 |
|
|
drupal_render($form['remove_flags'][$i]),
|
1044 |
|
|
drupal_render($form['mapping_weight'][$i]),
|
1045 |
|
|
),
|
1046 |
|
|
'class' => array('draggable', 'tabledrag-leaf'),
|
1047 |
|
|
);
|
1048 |
|
|
}
|
1049 |
|
|
}
|
1050 |
|
|
if (!count($rows)) {
|
1051 |
|
|
$rows[] = array(
|
1052 |
|
|
array(
|
1053 |
|
|
'colspan' => 5,
|
1054 |
|
|
'data' => t('No mappings defined.'),
|
1055 |
|
|
),
|
1056 |
|
|
);
|
1057 |
|
|
}
|
1058 |
|
|
$rows[] = array(
|
1059 |
|
|
drupal_render($form['source']),
|
1060 |
|
|
drupal_render($form['target']),
|
1061 |
|
|
'',
|
1062 |
|
|
drupal_render($form['add']),
|
1063 |
|
|
'',
|
1064 |
|
|
);
|
1065 |
41cc1b08
|
Assos Assos
|
$output = '';
|
1066 |
|
|
if (!empty($form['changed'])) {
|
1067 |
|
|
// This form element is only available if target configuration changed.
|
1068 |
|
|
$output .= drupal_render($form['changed']);
|
1069 |
|
|
}
|
1070 |
|
|
$output .= '<div class="help feeds-admin-ui">' . drupal_render($form['help']) . '</div>';
|
1071 |
85ad3d82
|
Assos Assos
|
$output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'feeds-ui-mapping-overview')));
|
1072 |
|
|
|
1073 |
|
|
// Build the help table that explains available sources.
|
1074 |
|
|
$legend = '';
|
1075 |
|
|
$rows = array();
|
1076 |
|
|
foreach (element_children($form['legendset']['legend']['sources']) as $k) {
|
1077 |
|
|
$rows[] = array(
|
1078 |
|
|
check_plain(drupal_render($form['legendset']['legend']['sources'][$k]['name'])),
|
1079 |
|
|
check_plain(drupal_render($form['legendset']['legend']['sources'][$k]['description'])),
|
1080 |
|
|
);
|
1081 |
|
|
}
|
1082 |
|
|
if (count($rows)) {
|
1083 |
|
|
$legend .= '<h4>' . t('Sources') . '</h4>';
|
1084 |
|
|
$legend .= theme('table', array('header' => array(t('Name'), t('Description')), 'rows' => $rows));
|
1085 |
|
|
}
|
1086 |
|
|
|
1087 |
|
|
// Build the help table that explains available targets.
|
1088 |
|
|
$rows = array();
|
1089 |
|
|
foreach (element_children($form['legendset']['legend']['targets']) as $k) {
|
1090 |
|
|
$rows[] = array(
|
1091 |
41cc1b08
|
Assos Assos
|
check_plain(drupal_render($form['legendset']['legend']['targets'][$k]['name']) . ' (' . $k . ')'),
|
1092 |
85ad3d82
|
Assos Assos
|
check_plain(drupal_render($form['legendset']['legend']['targets'][$k]['description'])),
|
1093 |
|
|
);
|
1094 |
|
|
}
|
1095 |
|
|
$legend .= '<h4>' . t('Targets') . '</h4>';
|
1096 |
|
|
$legend .= theme('table', array('header' => array(t('Name'), t('Description')), 'rows' => $rows));
|
1097 |
|
|
|
1098 |
|
|
// Stick tables into collapsible fieldset.
|
1099 |
|
|
$form['legendset']['legend'] = array(
|
1100 |
|
|
'#markup' => '<div>' . $legend . '</div>',
|
1101 |
|
|
);
|
1102 |
|
|
|
1103 |
|
|
$output .= drupal_render($form['legendset']);
|
1104 |
|
|
$output .= drupal_render_children($form);
|
1105 |
|
|
|
1106 |
|
|
drupal_add_tabledrag('feeds-ui-mapping-overview', 'order', 'sibling', 'feeds-ui-mapping-weight');
|
1107 |
|
|
return $output;
|
1108 |
|
|
}
|
1109 |
|
|
|
1110 |
|
|
/**
|
1111 |
|
|
* Page callback to import a Feeds importer.
|
1112 |
|
|
*/
|
1113 |
|
|
function feeds_ui_importer_import($form, &$form_state) {
|
1114 |
|
|
$form['id'] = array(
|
1115 |
|
|
'#type' => 'textfield',
|
1116 |
|
|
'#title' => t('Importer id'),
|
1117 |
|
|
'#description' => t('Enter the id to use for this importer if it is different from the source importer. Leave blank to use the id of the importer.'),
|
1118 |
|
|
);
|
1119 |
|
|
$form['id_override'] = array(
|
1120 |
|
|
'#type' => 'checkbox',
|
1121 |
|
|
'#title' => t('Replace an existing importer if one exists with the same id.'),
|
1122 |
|
|
);
|
1123 |
|
|
$form['bypass_validation'] = array(
|
1124 |
|
|
'#type' => 'checkbox',
|
1125 |
|
|
'#title' => t('Bypass importer validation'),
|
1126 |
|
|
'#description' => t('Bypass the validation of plugins when importing.'),
|
1127 |
|
|
);
|
1128 |
|
|
$form['importer'] = array(
|
1129 |
|
|
'#type' => 'textarea',
|
1130 |
|
|
'#rows' => 10,
|
1131 |
|
|
);
|
1132 |
|
|
$form['actions'] = array('#type' => 'actions');
|
1133 |
|
|
$form['actions']['submit'] = array(
|
1134 |
|
|
'#type' => 'submit',
|
1135 |
|
|
'#value' => t('Import'),
|
1136 |
|
|
);
|
1137 |
|
|
return $form;
|
1138 |
|
|
}
|
1139 |
|
|
|
1140 |
|
|
/**
|
1141 |
|
|
* Form validation handler for feeds_ui_importer_import().
|
1142 |
|
|
*
|
1143 |
|
|
* @see feeds_ui_importer_import_submit()
|
1144 |
|
|
*/
|
1145 |
|
|
function feeds_ui_importer_import_validate($form, &$form_state) {
|
1146 |
|
|
$form_state['values']['importer'] = trim($form_state['values']['importer']);
|
1147 |
|
|
$form_state['values']['id'] = trim($form_state['values']['id']);
|
1148 |
|
|
|
1149 |
|
|
if (!empty($form_state['values']['id']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['id'])) {
|
1150 |
|
|
form_error($form['id'], t('Feeds importer id must be alphanumeric with underscores only.'));
|
1151 |
|
|
}
|
1152 |
|
|
|
1153 |
|
|
if (substr($form_state['values']['importer'], 0, 5) == '<?php') {
|
1154 |
|
|
$form_state['values']['importer'] = substr($form_state['values']['importer'], 5);
|
1155 |
|
|
}
|
1156 |
|
|
|
1157 |
|
|
$feeds_importer = NULL;
|
1158 |
|
|
ob_start();
|
1159 |
|
|
eval($form_state['values']['importer']);
|
1160 |
|
|
ob_end_clean();
|
1161 |
|
|
|
1162 |
|
|
if (!is_object($feeds_importer)) {
|
1163 |
|
|
return form_error($form['importer'], t('Unable to interpret Feeds importer code.'));
|
1164 |
|
|
}
|
1165 |
|
|
|
1166 |
|
|
if (empty($feeds_importer->api_version) || $feeds_importer->api_version < 1) {
|
1167 |
|
|
form_error($form['importer'], t('The importer is not compatible with this version of Feeds.'));
|
1168 |
|
|
}
|
1169 |
|
|
elseif (version_compare($feeds_importer->api_version, feeds_api_version(), '>')) {
|
1170 |
|
|
form_error($form['importer'], t('That importer is created for the version %import_version of Feeds, but you only have version %api_version.', array(
|
1171 |
|
|
'%import_version' => $feeds_importer->api_version,
|
1172 |
|
|
'%api_version' => feeds_api_version())));
|
1173 |
|
|
}
|
1174 |
|
|
|
1175 |
41cc1b08
|
Assos Assos
|
// Change to user-supplied id.
|
1176 |
|
|
if ($form_state['values']['id']) {
|
1177 |
|
|
$feeds_importer->id = $form_state['values']['id'];
|
1178 |
|
|
}
|
1179 |
|
|
|
1180 |
|
|
$exists = feeds_ui_importer_machine_name_exists($feeds_importer->id);
|
1181 |
|
|
|
1182 |
|
|
if ($exists && !$form_state['values']['id_override']) {
|
1183 |
|
|
if (feeds_importer($feeds_importer->id)->export_type != EXPORT_IN_CODE) {
|
1184 |
|
|
return form_error($form['id'], t('Feeds importer already exists with that id.'));
|
1185 |
|
|
}
|
1186 |
85ad3d82
|
Assos Assos
|
}
|
1187 |
|
|
|
1188 |
|
|
if (!$form_state['values']['bypass_validation']) {
|
1189 |
|
|
foreach (array('fetcher', 'parser', 'processor') as $type) {
|
1190 |
|
|
$plugin = feeds_plugin($feeds_importer->config[$type]['plugin_key'], $feeds_importer->id);
|
1191 |
|
|
if (get_class($plugin) == 'FeedsMissingPlugin') {
|
1192 |
|
|
form_error($form['importer'], t('The plugin %plugin is unavailable.', array('%plugin' => $feeds_importer->config[$type]['plugin_key'])));
|
1193 |
|
|
}
|
1194 |
|
|
}
|
1195 |
|
|
}
|
1196 |
|
|
|
1197 |
|
|
$form_state['importer'] = $feeds_importer;
|
1198 |
|
|
}
|
1199 |
|
|
|
1200 |
|
|
/**
|
1201 |
|
|
* Form submission handler for feeds_ui_importer_import().
|
1202 |
|
|
*
|
1203 |
|
|
* @see feeds_ui_importer_import_validate()
|
1204 |
|
|
*/
|
1205 |
|
|
function feeds_ui_importer_import_submit($form, &$form_state) {
|
1206 |
|
|
$importer = $form_state['importer'];
|
1207 |
41cc1b08
|
Assos Assos
|
|
1208 |
|
|
// Create a copy of the importer to preserve config.
|
1209 |
|
|
$save = feeds_importer($importer->id);
|
1210 |
|
|
$save->setConfig($importer->config);
|
1211 |
85ad3d82
|
Assos Assos
|
foreach (array('fetcher', 'parser', 'processor') as $type) {
|
1212 |
41cc1b08
|
Assos Assos
|
$save->setPlugin($importer->config[$type]['plugin_key']);
|
1213 |
|
|
$save->$type->setConfig($importer->config[$type]['config']);
|
1214 |
85ad3d82
|
Assos Assos
|
}
|
1215 |
41cc1b08
|
Assos Assos
|
$save->save();
|
1216 |
85ad3d82
|
Assos Assos
|
|
1217 |
|
|
drupal_set_message(t('Successfully imported the %id feeds importer.', array('%id' => $importer->id)));
|
1218 |
|
|
$form_state['redirect'] = 'admin/structure/feeds';
|
1219 |
|
|
} |