1
|
<?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
|
function feeds_ui_edit_page(FeedsImporter $importer, $active = 'help', $plugin_key = '') {
|
277
|
// Get plugins and configuration.
|
278
|
$plugins = FeedsPlugin::all();
|
279
|
|
280
|
$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
|
|
295
|
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
|
|
302
|
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
|
|
317
|
case 'mapping':
|
318
|
$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
|
$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
|
$fetcher = isset($plugins[$config['fetcher']['plugin_key']]) ? $plugins[$config['fetcher']['plugin_key']] : $plugins['FeedsMissingPlugin'];
|
354
|
$actions = array();
|
355
|
if ($importer->fetcher->hasConfigForm()) {
|
356
|
$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
|
$parser = isset($plugins[$config['parser']['plugin_key']]) ? $plugins[$config['parser']['plugin_key']] : $plugins['FeedsMissingPlugin'];
|
371
|
$actions = array();
|
372
|
if ($importer->parser->hasConfigForm()) {
|
373
|
$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
|
$processor = isset($plugins[$config['processor']['plugin_key']]) ? $plugins[$config['processor']['plugin_key']] : $plugins['FeedsMissingPlugin'];
|
388
|
$actions = array();
|
389
|
if ($importer->processor->hasConfigForm()) {
|
390
|
$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
|
// 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
|
// 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
|
$settings_form = array();
|
638
|
|
639
|
foreach ($target['form_callbacks'] as $callback) {
|
640
|
$settings_form += call_user_func($callback, $mapping, $target, $form, $form_state);
|
641
|
}
|
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
|
$summary = array();
|
666
|
|
667
|
foreach ($target['summary_callbacks'] as $callback) {
|
668
|
$summary[] = call_user_func($callback, $mapping, $target, $form, $form_state);
|
669
|
}
|
670
|
|
671
|
// Filter out empty summary values.
|
672
|
$summary = implode('<br />', array_filter($summary));
|
673
|
|
674
|
// 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
|
return array();
|
697
|
}
|
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
|
if (!strlen($form_state['values']['source']) xor !strlen($form_state['values']['target'])) {
|
737
|
|
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
|
if (!strlen($form_state['values']['source'])) {
|
745
|
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
|
if (strlen($form_state['values']['source']) && strlen($form_state['values']['target'])) {
|
809
|
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
|
$result[$k] = $v['name'] . ' (' . $k . ')';
|
838
|
}
|
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
|
// Add indicator to target if target configuration changed.
|
1035
|
if (isset($form['#mapping_settings'][$i])) {
|
1036
|
$target .= '<span class="warning">*</span>';
|
1037
|
}
|
1038
|
$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
|
$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
|
$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
|
check_plain(drupal_render($form['legendset']['legend']['targets'][$k]['name']) . ' (' . $k . ')'),
|
1092
|
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
|
// 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
|
}
|
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
|
|
1208
|
// Create a copy of the importer to preserve config.
|
1209
|
$save = feeds_importer($importer->id);
|
1210
|
$save->setConfig($importer->config);
|
1211
|
foreach (array('fetcher', 'parser', 'processor') as $type) {
|
1212
|
$save->setPlugin($importer->config[$type]['plugin_key']);
|
1213
|
$save->$type->setConfig($importer->config[$type]['config']);
|
1214
|
}
|
1215
|
$save->save();
|
1216
|
|
1217
|
drupal_set_message(t('Successfully imported the %id feeds importer.', array('%id' => $importer->id)));
|
1218
|
$form_state['redirect'] = 'admin/structure/feeds';
|
1219
|
}
|