Projet

Général

Profil

Paste
Télécharger (21,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / feeds / feeds.api.php @ ed9a13f1

1
<?php
2

    
3
/**
4
 * @file
5
 * Documentation of Feeds hooks.
6
 */
7

    
8
/**
9
 * @defgroup pluginapi Plugin API
10
 * @{
11
 * Feeds offers a CTools based plugin API.
12
 *
13
 * Fetchers, parsers and processors are declared to Feeds as plugins.
14
 *
15
 * @see feeds_feeds_plugins()
16
 * @see FeedsFetcher
17
 * @see FeedsParser
18
 * @see FeedsProcessor
19
 */
20

    
21
/**
22
 * CTools plugin hook example.
23
 *
24
 * This example of a CTools plugin hook needs to be implemented to make
25
 * hook_feeds_plugins() discoverable by CTools and Feeds. The hook specifies
26
 * that the hook_feeds_plugins() returns Feeds Plugin API version 1 style
27
 * plugins.
28
 */
29
function hook_ctools_plugin_api($owner, $api) {
30
  if ($owner == 'feeds' && $api == 'plugins') {
31
    return array('version' => 1);
32
  }
33
}
34

    
35
/**
36
 * Declare Feeds plugins.
37
 *
38
 * Implement this hook to declare Fetcher, Parser or Processor plugins for
39
 * Feeds. For a working example implementation, see feeds_feeds_plugin().
40
 * In order for this hook to be invoked, you MUST implement
41
 * hook_ctools_plugin_api() as well.
42
 *
43
 * @see feeds_feeds_plugin()
44
 */
45
function hook_feeds_plugins() {
46
  $info = array();
47
  $info['MyFetcher'] = array(
48
    'name' => 'My Fetcher',
49
    'description' => 'Fetches my stuff.',
50
    'help' => 'More verbose description here. Will be displayed on fetcher selection menu.',
51
    'handler' => array(
52
      'parent' => 'FeedsFetcher',
53
      'class' => 'MyFetcher',
54
      'file' => 'MyFetcher.inc',
55
      // Feeds will look for MyFetcher.inc in the my_module directory.
56
      'path' => drupal_get_path('module', 'my_module'),
57
    ),
58
  );
59
  $info['MyParser'] = array(
60
    'name' => 'ODK parser',
61
    'description' => 'Parse my stuff.',
62
    'help' => 'More verbose description here. Will be displayed on parser selection menu.',
63
    'handler' => array(
64
      // Being directly or indirectly an extension of FeedsParser makes a plugin
65
      // a parser plugin.
66
      'parent' => 'FeedsParser',
67
      'class' => 'MyParser',
68
      'file' => 'MyParser.inc',
69
      'path' => drupal_get_path('module', 'my_module'),
70
    ),
71
  );
72
  $info['MyProcessor'] = array(
73
    'name' => 'ODK parser',
74
    'description' => 'Process my stuff.',
75
    'help' => 'More verbose description here. Will be displayed on processor selection menu.',
76
    'handler' => array(
77
      'parent' => 'FeedsProcessor',
78
      'class' => 'MyProcessor',
79
      'file' => 'MyProcessor.inc',
80
      'path' => drupal_get_path('module', 'my_module'),
81
    ),
82
  );
83
  return $info;
84
}
85

    
86
/**
87
 * @} End of "defgroup pluginapi".
88
 */
89

    
90
/**
91
 * @defgroup import Import and clear hooks
92
 * @{
93
 */
94

    
95
/**
96
 * Invoked after a feed source has been parsed, before it will be processed.
97
 *
98
 * @param FeedsSource $source
99
 *   FeedsSource object that describes the source that has been imported.
100
 * @param FeedsParserResult $result
101
 *   FeedsParserResult object that has been parsed from the source.
102
 */
103
function hook_feeds_after_parse(FeedsSource $source, FeedsParserResult $result) {
104
  // For example, set title of imported content:
105
  $result->title = 'Import number ' . my_module_import_id();
106
}
107

    
108
/**
109
 * Invoked before a feed source import starts.
110
 *
111
 * @param FeedsSource $source
112
 *   FeedsSource object that describes the source that is going to be imported.
113
 */
114
function hook_feeds_before_import(FeedsSource $source) {
115
  // See feeds_rules module's implementation for an example.
116
}
117

    
118
/**
119
 * Invoked before a feed item is updated/created/replaced.
120
 *
121
 * This is called every time a feed item is processed no matter if the item gets
122
 * updated or not.
123
 *
124
 * @param FeedsSource $source
125
 *   The source for the current feed.
126
 * @param array $item
127
 *   All the current item from the feed.
128
 * @param int|null $entity_id
129
 *   The id of the current item which is going to be updated. If this is a new
130
 *   item, then NULL is passed.
131
 */
132
function hook_feeds_before_update(FeedsSource $source, $item, $entity_id) {
133
  if ($entity_id) {
134
    $processor = $source->importer->processor;
135
    db_update('foo_bar')
136
      ->fields(array(
137
        'entity_type' => $processor->entityType(),
138
        'entity_id' => $entity_id,
139
        'last_seen' => REQUEST_TIME,
140
      ))
141
      ->condition('entity_type', $processor->entityType())
142
      ->condition('entity_id', $entity_id)
143
      ->execute();
144
  }
145
}
146

    
147
/**
148
 * Invoked before a feed item is validated.
149
 *
150
 * @param FeedsSource $source
151
 *   FeedsSource object that describes the source that is being imported.
152
 * @param object $entity
153
 *   The entity object.
154
 * @param array $item
155
 *   The parser result for this entity.
156
 * @param int|null $entity_id
157
 *   The id of the current item which is going to be updated. If this is a new
158
 *   item, then NULL is passed.
159
 */
160
function hook_feeds_prevalidate(FeedsSource $source, $entity, $item, $entity_id) {
161
  // Correct a field value to make it pass validation.
162
  if (isset($entity->myfield)) {
163
    foreach ($entity->myfield as $language => &$values) {
164
      // There are only three values allowed. Throw away the rest.
165
      if (count($values) > 3) {
166
        $values = array_slice($values, 0, 3);
167
      }
168
    }
169
  }
170
}
171

    
172
/**
173
 * Invoked before a feed item is saved.
174
 *
175
 * @param FeedsSource $source
176
 *   FeedsSource object that describes the source that is being imported.
177
 * @param object $entity
178
 *   The entity object.
179
 * @param array $item
180
 *   The parser result for this entity.
181
 * @param int|null $entity_id
182
 *   The id of the current item which is going to be updated. If this is a new
183
 *   item, then NULL is passed.
184
 */
185
function hook_feeds_presave(FeedsSource $source, $entity, $item, $entity_id) {
186
  if ($entity->feeds_item->entity_type == 'node') {
187
    // Skip saving this entity.
188
    $entity->feeds_item->skip = TRUE;
189
  }
190
}
191

    
192
/**
193
 * Invoked after a feed item has been saved.
194
 *
195
 * @param FeedsSource $source
196
 *   FeedsSource object that describes the source that is being imported.
197
 * @param object $entity
198
 *   The entity object that has just been saved.
199
 * @param array $item
200
 *   The parser result for this entity.
201
 * @param int|null $entity_id
202
 *   The id of the current item which is going to be updated. If this is a new
203
 *   item, then NULL is passed.
204
 */
205
function hook_feeds_after_save(FeedsSource $source, $entity, $item, $entity_id) {
206
  // Although the $entity object is passed by reference, any changes made in
207
  // this function will be ignored by the FeedsProcessor.
208
  $config = $source->importer->getConfig();
209

    
210
  if ($config['processor']['config']['purge_unseen_items'] && isset($entity->feeds_item)) {
211
    $feeds_item = $entity->feeds_item;
212
    $feeds_item->batch_id = feeds_delete_get_current_batch($feeds_item->feed_nid);
213

    
214
    drupal_write_record('feeds_delete_item', $feeds_item);
215
  }
216
}
217

    
218
/**
219
 * Invoked after a feed source has been imported.
220
 *
221
 * @param FeedsSource $source
222
 *   FeedsSource object that describes the source that has been imported.
223
 */
224
function hook_feeds_after_import(FeedsSource $source) {
225
  // We can also check for an exception in this hook. The exception should not
226
  // be thrown here, Feeds will handle it.
227
  if (isset($source->exception)) {
228
    watchdog('mymodule', 'An exception occurred during importing!', array(), WATCHDOG_ERROR);
229
    mymodule_panic_reaction($source);
230
  }
231
}
232

    
233
/**
234
 * Invoked after a feed source has been cleared of its items.
235
 *
236
 * @param FeedsSource $source
237
 *   FeedsSource object that describes the source that has been cleared.
238
 */
239
function hook_feeds_after_clear(FeedsSource $source) {
240
}
241

    
242
/**
243
 * @} End of "defgroup import".
244
 */
245

    
246
/**
247
 * @defgroup mappingapi Mapping API
248
 * @{
249
 */
250

    
251
/**
252
 * Alter mapping sources.
253
 *
254
 * Use this hook to add additional mapping sources for any parser. Allows for
255
 * registering a callback to be invoked at mapping time.
256
 *
257
 * @see my_source_get_source()
258
 * @see locale_feeds_parser_sources_alter()
259
 */
260
function hook_feeds_parser_sources_alter(&$sources, $content_type) {
261
  $sources['my_source'] = array(
262
    'name' => t('Images in description element'),
263
    'description' => t('Images occurring in the description element of a feed item.'),
264
    'callback' => 'callback_my_source_get_source',
265
  );
266
}
267

    
268
/**
269
 * Returns a value to use as a mapping source.
270
 *
271
 * Callback for hook_feeds_parser_sources_alter().
272
 *
273
 * This function is called on mapping time.
274
 *
275
 * @param FeedsSource $source
276
 *   The FeedsSource object being imported.
277
 * @param FeedsParserResult $result
278
 *   The FeedsParserResult object being mapped from.
279
 * @param string $key
280
 *   The key specified in the $sources array in
281
 *   hook_feeds_parser_sources_alter().
282
 *
283
 * @return mixed
284
 *   The value to be extracted from the source.
285
 *
286
 * @see hook_feeds_parser_sources_alter()
287
 * @see locale_feeds_get_source()
288
 *
289
 * @ingroup callbacks
290
 */
291
function callback_my_source_get_source(FeedsSource $source, FeedsParserResult $result, $key) {
292
  $item = $result->currentItem();
293
  return my_source_parse_images($item['description']);
294
}
295

    
296
/**
297
 * Adds mapping targets for processors.
298
 *
299
 * This hook allows additional target options to be added to the processors
300
 * mapping form.
301
 *
302
 * If the key in $targets[] does not correspond to the actual key on the node
303
 * object ($node->key), real_target MUST be specified. See mappers/link.inc
304
 *
305
 * For an example implementation, see mappers/text.inc
306
 *
307
 * @param string $entity_type
308
 *   The entity type of the target, for instance a 'node' entity.
309
 * @param string $bundle
310
 *   The entity bundle to return targets for.
311
 *
312
 * @return array
313
 *   An array whose keys are the target name and whose values are arrays
314
 *   containing the following keys:
315
 *   - name: A human readable, translated label for the target.
316
 *   - description: (optional) A human readable, translated description for the
317
 *     target.
318
 *   - callback: The callback used to set the value on the target.
319
 *   - real_target: (optional) the name of the property on the entity that will
320
 *     be set by the callback. Specify this if the target name is not equal to
321
 *     the entity property name. This information will be used to clear the
322
 *     right target at the beginning of the mapping process.
323
 *   - optional_unique: (optional) A boolean that indicates whether or not the
324
 *     target can be used as an unique target. If you set this to TRUE, be sure
325
 *     to also specify "unique_callbacks".
326
 *   - unique_callbacks: (optional) An array of callbacks that are used to
327
 *     retrieve existing entity ids. Existing entities can be updated based on
328
 *     unique targets.
329
 *   - form_callbacks: (optional) An array of callbacks that are used to return
330
 *     a form with additional configuration for a target.
331
 *   - summary_callbacks: (optional) An array of callbacks that are used to
332
 *     display values of additional target configuration.
333
 *   - preprocess_callbacks: (optional) An array of callbacks that are used to
334
 *     set or change mapping options.
335
 *   - deprecated: (optional) A boolean that if TRUE, hides the target from the
336
 *     UI. Use this if you want to rename targets for consistency, but don't
337
 *     want to break importers that are using the old target name. If an
338
 *     importer uses this target it will show up as "DEPRECATED" in the UI.
339
 */
340
function hook_feeds_processor_targets($entity_type, $bundle) {
341
  $targets = array();
342

    
343
  if ($entity_type == 'node') {
344
    // Example 1: provide the minimal info for a target. Description is
345
    // optional, but recommended.
346
    // @see my_module_set_target()
347
    $targets['my_node_field'] = array(
348
      'name' => t('My custom node field'),
349
      'description' => t('Description of what my custom node field does.'),
350
      'callback' => 'callback_my_module_set_target',
351
    );
352

    
353
    // Example 2: specify "real_target" if the target name is different from
354
    // the entity property name.
355
    // Here the target is called "my_node_field2:uri", but the entity property
356
    // is called "my_node_field2". This will ensure that the property
357
    // "my_node_field2" is cleared out that the beginning of the mapping
358
    // process.
359
    $targets['my_node_field2:uri'] = array(
360
      'name' => t('My third custom node field'),
361
      'description' => t('A target that sets a property that does not have the same name as the target.'),
362
      'callback' => 'my_module_set_target2',
363
      'real_target' => 'my_node_field2',
364
    );
365

    
366
    // Example 3: you can make your target selectable as an unique target by
367
    // setting "optional_unique" to TRUE and specify one or more callbacks to
368
    // retrieve existing entity id's.
369
    // @see my_module_mapper_unique()
370
    $targets['my_node_field3'] = array(
371
      'name' => t('My third custom node field'),
372
      'description' => t('A field that can be set as an unique target.'),
373
      'callback' => 'my_module_set_target3',
374
      'optional_unique' => TRUE,
375
      'unique_callbacks' => array('callback_my_module_mapper_unique'),
376
    );
377

    
378
    // Example 4: use the form and summary callbacks to add additional
379
    // configuration options for your target. Use the form callbacks to provide
380
    // a form to set the target configuration. Use the summary callbacks to
381
    // display the target configuration.
382
    // @see my_module_form_callback()
383
    // @see my_module_summary_callback()
384
    $targets['my_node_field4'] = array(
385
      'name' => t('My fourth custom node field'),
386
      'description' => t('A field with additional configuration.'),
387
      'callback' => 'my_module_set_target4',
388
      'form_callbacks' => array('callback_my_module_form_callback'),
389
      'summary_callbacks' => array('callback_my_module_summary_callback'),
390
    );
391

    
392
    // Example 5: use preprocess callbacks to set or change mapping options.
393
    // @see my_module_preprocess_callback()
394
    $targets['my_node_field5'] = array(
395
      'name' => t('My fifth custom node field'),
396
      'description' => t('A field with additional configuration.'),
397
      'callback' => 'my_module_set_target5',
398
      'preprocess_callbacks' => array('callback_my_module_preprocess_callback'),
399
    );
400

    
401
    // Example 6: when you want to remove or rename previously provided targets,
402
    // you can set "deprecated" to TRUE for the old target name. This will make
403
    // the target to be no longer selectable in the UI. If an importer uses this
404
    // target it will show up as "DEPRECATED" in the UI.
405
    // If you want that the target continues to work, you can still specify the
406
    // callback.
407
    $targets['deprecated_target'] = array(
408
      'name' => t('A target that cannot be chosen in the UI.'),
409
      'deprecated' => TRUE,
410
    );
411
  }
412

    
413
  return $targets;
414
}
415

    
416
/**
417
 * Alters the target array.
418
 *
419
 * This hook allows modifying the target array.
420
 *
421
 * @param array &$targets
422
 *   Array containing the targets to be offered to the user. Add to this array
423
 *   to expose additional options.
424
 * @param string $entity_type
425
 *   The entity type of the target, for instance a 'node' entity.
426
 * @param string $bundle
427
 *   The entity bundle to return targets for.
428
 *
429
 * @see hook_feeds_processor_targets()
430
 */
431
function hook_feeds_processor_targets_alter(array &$targets, $entity_type, $bundle) {
432
  // Example: set an existing target as optional unique.
433
  if ($entity_type == 'node' && $bundle == 'article') {
434
    if (isset($targets['nid'])) {
435
      $targets['nid']['unique_callbacks'][] = 'my_module_mapper_unique';
436
      $targets['nid']['optional_unique'] = TRUE;
437
    }
438
  }
439
}
440

    
441
/**
442
 * Sets a value on a target.
443
 *
444
 * Callback for hook_feeds_processor_targets().
445
 *
446
 * This callback is specified on the 'callback' key of the target definition.
447
 * A target can for example be a field or property on an entity.
448
 *
449
 * @param FeedsSource $source
450
 *   Field mapper source settings.
451
 * @param object $entity
452
 *   An entity object, for instance a node object.
453
 * @param string $target
454
 *   A string identifying the target on the node.
455
 * @param array $values
456
 *   The value to populate the target with.
457
 * @param array $mapping
458
 *   Associative array of the mapping settings from the per mapping
459
 *   configuration form.
460
 *
461
 * @see hook_feeds_processor_targets()
462
 *
463
 * @ingroup callbacks
464
 */
465
function callback_my_module_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
466
  $entity->{$target}[$entity->language][0]['value'] = reset($values);
467
  if (isset($source->importer->processor->config['input_format'])) {
468
    $entity->{$target}[$entity->language][0]['format'] = $source->importer->processor->config['input_format'];
469
  }
470
}
471

    
472
/**
473
 * Returns a form for configuring a target.
474
 *
475
 * Callback for hook_feeds_processor_targets().
476
 *
477
 * This callback is specified on the 'form_callbacks' key of the target
478
 * definition.
479
 * The arguments are the same that callback_my_module_summary_callback() gets.
480
 *
481
 * @return array
482
 *   The per mapping configuration form. Once the form is saved, $mapping will
483
 *   be populated with the form values.
484
 *
485
 * @see hook_feeds_processor_targets()
486
 * @see callback_my_module_summary_callback()
487
 *
488
 * @ingroup callbacks
489
 */
490
function callback_my_module_form_callback(array $mapping, $target, array $form, array $form_state) {
491
  return array(
492
    'my_setting' => array(
493
      '#type' => 'checkbox',
494
      '#title' => t('My setting checkbox'),
495
      '#default_value' => !empty($mapping['my_setting']),
496
    ),
497
  );
498
}
499

    
500
/**
501
 * Returns a string for displaying the target configuration.
502
 *
503
 * Callback for hook_feeds_processor_targets().
504
 *
505
 * This callback is specified on the 'summary_callbacks' key of the target
506
 * definition.
507
 * The arguments are the same that callback_my_module_form_callback() gets.
508
 *
509
 * @param array $mapping
510
 *   Associative array of the mapping settings.
511
 * @param string $target
512
 *   Array of target settings, as defined by the processor or
513
 *   hook_feeds_processor_targets_alter().
514
 * @param array $form
515
 *   The whole mapping form.
516
 * @param array $form_state
517
 *   The form state of the mapping form.
518
 *
519
 * @return string
520
 *   Returns, as a string that may contain HTML, the summary to display while
521
 *   the full form isn't visible.
522
 *   If the return value is empty, no summary and no option to view the form
523
 *   will be displayed.
524
 *
525
 * @see hook_feeds_processor_targets()
526
 * @see callback_my_module_form_callback()
527
 *
528
 * @ingroup callbacks
529
 */
530
function callback_my_module_summary_callback(array $mapping, $target, array $form, array $form_state) {
531
  if (empty($mapping['my_setting'])) {
532
    return t('My setting <strong>not</strong> active');
533
  }
534
  else {
535
    return t('My setting <strong>active</strong>');
536
  }
537
}
538

    
539
/**
540
 * Looks for an existing entity and returns an entity ID if found.
541
 *
542
 * Callback for hook_feeds_processor_targets().
543
 *
544
 * This callback is specified on the 'unique_callbacks' key of the target
545
 * definition.
546
 *
547
 * @param FeedsSource $source
548
 *   The Feed source.
549
 * @param string $entity_type
550
 *   Entity type for the entity to be processed.
551
 * @param string $bundle
552
 *   Bundle name for the entity to be processed.
553
 * @param string $target
554
 *   A string identifying the unique target on the entity.
555
 * @param array $values
556
 *   The unique values to be checked.
557
 *
558
 * @return int|null
559
 *   The existing entity id, or NULL if no existing entity is found.
560
 *
561
 * @see hook_feeds_processor_targets()
562
 * @see FeedsProcessor::existingEntityId()
563
 *
564
 * @ingroup callbacks
565
 */
566
function callback_my_module_mapper_unique(FeedsSource $source, $entity_type, $bundle, $target, array $values) {
567
  list($field_name, $column) = explode(':', $target . ':value');
568
  // Example for if the target is a field.
569
  $query = new EntityFieldQuery();
570
  $result = $query
571
    ->entityCondition('entity_type', $entity_type)
572
    ->entityCondition('bundle', $bundle)
573
    ->fieldCondition($field_name, $column, $values)
574
    ->execute();
575

    
576
  if (!empty($result[$entity_type])) {
577
    return key($result[$entity_type]);
578
  }
579
}
580

    
581
/**
582
 * Changes or sets a mapping option.
583
 *
584
 * Callback for hook_feeds_processor_targets().
585
 *
586
 * This callback is specified on the 'preprocess_callbacks' key of the target
587
 * definition.
588
 *
589
 * @param array $target
590
 *   The full target definition.
591
 * @param array &$mapping
592
 *   The mapping configuration.
593
 *
594
 * @see hook_feeds_processor_targets()
595
 *
596
 * @ingroup callbacks
597
 */
598
function callback_my_module_preprocess_callback(array $target, array &$mapping) {
599
  // Add in default values.
600
  $mapping += array('setting_value' => TRUE);
601
}
602

    
603
/**
604
 * Add additional configuration keys to FeedsConfigurable.
605
 *
606
 * This hooks allows you to add additional configuration keys to a
607
 * FeedsConfigurable. This is useful if you also implement a form alter hook to
608
 * provide extra options for existing Feeds plugins. By implementing one of the
609
 * Feeds hooks that are invoked during importing, you can act upon such setting.
610
 *
611
 * @param FeedsConfigurable $configurable
612
 *   The configurable item to add default configuration to.
613
 *
614
 * @return array
615
 *   Return an array of default configuration.
616
 */
617
function hook_feeds_config_defaults(FeedsConfigurable $configurable) {
618
  if ($configurable instanceof FeedsImporter) {
619
    return array(
620
      'my_module_extra_setting_1' => 0,
621
      'my_module_extra_setting_2' => NULL,
622
    );
623
  }
624
}
625

    
626
/**
627
 * A plugin-specific hook to add additional configuration keys.
628
 *
629
 * This hook can be used instead of the global hook_feeds_config_defaults() and
630
 * allows you to add additional configuration keys to a FeedsPlugin.
631
 *
632
 * The plugin type can be:
633
 * - fetcher;
634
 * - parser;
635
 * - processor.
636
 *
637
 * @param FeedsPlugin $plugin
638
 *   The plugin to add default configuration to.
639
 *
640
 * @return array
641
 *   Return an array of default configuration.
642
 *
643
 * @see hook_feeds_config_defaults()
644
 */
645
function hook_feeds_PLUGIN_TYPE_config_defaults(FeedsPlugin $plugin) {
646
  if ($plugin instanceof FeedsCSVParser) {
647
    return array(
648
      'extra_csv_parser_setting' => NULL,
649
    );
650
  }
651
}
652

    
653
/**
654
 * @} End of "defgroup mappingapi".
655
 */