source: sipes/modules_contrib/feeds/feeds.module @ ee98b7d

stableversion-3.0
Last change on this file since ee98b7d was 177a560, checked in by José Gregorio Puentes <jpuentes@…>, 8 años ago

se agrego el directorio de modulos contribuidos de drupal

  • Propiedad mode establecida a 100755
File size: 26.8 KB
Línea 
1<?php
2
3/**
4 * @file
5 * Feeds - basic API functions and hook implementations.
6 */
7
8// Common request time, use as point of reference and to avoid calls to time().
9define('FEEDS_REQUEST_TIME', time());
10// Do not schedule a feed for refresh.
11define('FEEDS_SCHEDULE_NEVER', -1);
12// Never expire feed items.
13define('FEEDS_EXPIRE_NEVER', -1);
14// An object that is not persistent. Compare EXPORT_IN_DATABASE, EXPORT_IN_CODE.
15define('FEEDS_EXPORT_NONE', 0x0);
16// Status of batched operations.
17define('FEEDS_BATCH_COMPLETE', 1);
18define('FEEDS_BATCH_ACTIVE', 0);
19
20/**
21 * @defgroup hooks Hook and callback implementations
22 * @{
23 */
24
25/**
26 * Implements hook_cron().
27 */
28function feeds_cron() {
29  if ($importers = feeds_reschedule()) {
30    foreach ($importers as $id) {
31      feeds_importer($id)->schedule();
32      $result = db_query("SELECT feed_nid FROM {feeds_source} WHERE id = '%s'", $id);
33      while ($row = db_fetch_object($result)) {
34        feeds_source($id, $row->feed_nid)->schedule();
35      }
36    }
37    feeds_reschedule(FALSE);
38    return;
39  }
40}
41
42/**
43 * Implementation of hook_cron_queue_info().
44 *
45 * Invoked by drupal_queue module if present.
46 */
47function feeds_cron_queue_info() {
48  $queues = array();
49  $queues['feeds_source_import'] = array(
50    'worker callback' => 'feeds_source_import',
51    'time' => variable_get('feeds_worker_time', 15),
52  );
53  $queues['feeds_importer_expire'] = array(
54    'worker callback' => 'feeds_importer_expire',
55    'time' => variable_get('feeds_worker_time', 15),
56  );
57  return $queues;
58}
59
60/**
61 * Scheduler callback for importing from a source.
62 */
63function feeds_source_import($job) {
64  $source = feeds_source($job['type'], $job['id']);
65  try {
66    $source->existing()->import();
67  }
68  catch (FeedsNotExistingException $e) {
69    // Do nothing.
70  }
71  catch (Exception $e) {
72    watchdog('feeds_source_import()', $e->getMessage(), array(), WATCHDOG_ERROR);
73  }
74  $source->schedule();
75}
76
77/**
78 * Scheduler callback for expiring content.
79 */
80function feeds_importer_expire($job) {
81  $importer = feeds_importer($job['type']);
82  try {
83    $importer->existing()->expire();
84  }
85  catch (FeedsNotExistingException $e) {
86    // Do nothing.
87  }
88  catch (Exception $e) {
89    watchdog('feeds_importer_expire()', $e->getMessage(), array(), WATCHDOG_ERROR);
90  }
91  $importer->schedule();
92}
93
94/**
95 * Reschedule one or all importers.
96 *
97 * Note: variable_set('feeds_reschedule', TRUE) is used in update hook
98 * feeds_update_6013() and as such must be maintained as part of the upgrade
99 * path from pre 6.x 1.0 beta 6 versions of Feeds.
100 *
101 * @param $importer_id
102 *   If TRUE, all importers will be rescheduled, if FALSE, no importers will
103 *   be rescheduled, if an importer id, only importer of that id will be
104 *   rescheduled.
105 *
106 * @return
107 *   TRUE if all importers need rescheduling. FALSE if no rescheduling is
108 *   required. An array of importers that need rescheduling.
109 */
110function feeds_reschedule($importer_id = NULL) {
111  $reschedule = variable_get('feeds_reschedule', FALSE);
112  if ($importer_id === TRUE || $importer_id === FALSE) {
113    $reschedule = $importer_id;
114  }
115  elseif (is_string($importer_id) && $reschedule !== TRUE) {
116    $reschedule = is_array($reschedule) ? $reschedule : array();
117    $reschedule[$importer_id] = $importer_id;
118  }
119  variable_set('feeds_reschedule', $reschedule);
120  if ($reschedule === TRUE) {
121    return feeds_enabled_importers();
122  }
123  return $reschedule;
124}
125
126/**
127 * Implementation of hook_perm().
128 */
129function feeds_perm() {
130  $perms = array('administer feeds');
131  foreach (feeds_importer_load_all() as $importer) {
132    $perms[] = 'import '. $importer->id .' feeds';
133    $perms[] = 'clear '. $importer->id .' feeds';
134  }
135  return $perms;
136}
137
138/**
139 * Implementation of hook_forms().
140 *
141 * Declare form callbacks for all known classes derived from FeedsConfigurable.
142 */
143function feeds_forms() {
144  $forms = array();
145  $forms['FeedsImporter_feeds_form']['callback'] = 'feeds_form';
146  $plugins = feeds_get_plugins();
147  foreach ($plugins as $plugin) {
148    $forms[$plugin['handler']['class'] .'_feeds_form']['callback'] = 'feeds_form';
149  }
150  return $forms;
151}
152
153/**
154 * Implementation of hook_menu().
155 */
156function feeds_menu() {
157  // Register a callback for all feed configurations that are not attached to a content type.
158  $items = array();
159  foreach (feeds_importer_load_all() as $importer) {
160    if (empty($importer->config['content_type'])) {
161      $items['import/'. $importer->id] = array(
162        'title' => $importer->config['name'],
163        'page callback' => 'drupal_get_form',
164        'page arguments' => array('feeds_import_form', 1),
165        'access callback' => 'feeds_access',
166        'access arguments' => array('import', $importer->id),
167        'file' => 'feeds.pages.inc',
168      );
169      $items['import/'. $importer->id .'/import'] = array(
170        'title' => 'Import',
171        'type' => MENU_DEFAULT_LOCAL_TASK,
172        'weight' => -10,
173      );
174      $items['import/'. $importer->id .'/delete-items'] = array(
175        'title' => 'Delete items',
176        'page callback' => 'drupal_get_form',
177        'page arguments' => array('feeds_delete_tab_form', 1),
178        'access callback' => 'feeds_access',
179        'access arguments' => array('clear', $importer->id),
180        'file' => 'feeds.pages.inc',
181        'type' => MENU_LOCAL_TASK,
182      );
183    }
184    else {
185      $items['node/%node/import'] = array(
186        'title' => 'Import',
187        'page callback' => 'drupal_get_form',
188        'page arguments' => array('feeds_import_tab_form', 1),
189        'access callback' => 'feeds_access',
190        'access arguments' => array('import', 1),
191        'file' => 'feeds.pages.inc',
192        'type' => MENU_LOCAL_TASK,
193        'weight' => 10,
194      );
195      $items['node/%node/delete-items'] = array(
196        'title' => 'Delete items',
197        'page callback' => 'drupal_get_form',
198        'page arguments' => array('feeds_delete_tab_form', NULL, 1),
199        'access callback' => 'feeds_access',
200        'access arguments' => array('clear', 1),
201        'file' => 'feeds.pages.inc',
202        'type' => MENU_LOCAL_TASK,
203        'weight' => 11,
204      );
205    }
206    $items += $importer->fetcher->menuItem();
207  }
208  if (count($items)) {
209    $items['import'] = array(
210      'title' => 'Import',
211      'page callback' => 'feeds_page',
212      'access callback' => 'feeds_page_access',
213      'file' => 'feeds.pages.inc',
214    );
215  }
216  return $items;
217}
218
219/**
220 * Menu loader callback.
221 */
222function feeds_importer_load($id) {
223  return feeds_importer($id);
224}
225
226/**
227 * Implementation of hook_theme().
228 */
229function feeds_theme() {
230  return array(
231    'feeds_upload' => array(
232      'file' => 'feeds.pages.inc',
233    ),
234  );
235}
236
237/**
238 * Menu access callback.
239 *
240 * @param $action
241 *   The action to be performed. Possible values are:
242 *   - import
243 *   - clear
244 * @param $param
245 *   Node object or FeedsImporter id.
246 */
247function feeds_access($action, $param) {
248  if (!in_array($action, array('import', 'clear'))) {
249    // If $action is not one of the supported actions, we return access denied.
250    return FALSE;
251  }
252
253  if (is_string($param)) {
254    $importer_id = $param;
255  }
256  elseif ($param->type) {
257    $importer_id = feeds_get_importer_id($param->type);
258  }
259
260  // Check for permissions if feed id is present, otherwise return FALSE.
261  if ($importer_id) {
262    if (user_access('administer feeds') || user_access($action .' '. $importer_id .' feeds')) {
263      return TRUE;
264    }
265  }
266  return FALSE;
267}
268
269/**
270 * Menu access callback.
271 */
272function feeds_page_access() {
273  if (user_access('administer feeds')) {
274    return TRUE;
275  }
276  foreach (feeds_enabled_importers() as $id) {
277    if (user_access("import $id feeds")) {
278      return TRUE;
279    }
280  }
281  return FALSE;
282}
283
284/**
285 * Implementation of hook_views_api().
286 */
287function feeds_views_api() {
288  return array(
289    'api' => '2.0',
290    'path' => drupal_get_path('module', 'feeds') .'/views',
291  );
292}
293
294/**
295 * Implementation of hook_ctools_plugin_api().
296 */
297function feeds_ctools_plugin_api($owner, $api) {
298  if ($owner == 'feeds' && $api == 'plugins') {
299    return array('version' => 1);
300  }
301}
302
303/**
304 * Implementation of hook_ctools_plugin_plugins().
305 *
306 * Psuedo hook defintion plugin system options and defaults.
307 */
308function feeds_ctools_plugin_plugins() {
309  return array(
310    'cache' => TRUE,
311    'use hooks' => TRUE,
312  );
313}
314
315/**
316 * Implementation of hook_feeds_plugins().
317 */
318function feeds_feeds_plugins() {
319  module_load_include('inc', 'feeds', 'feeds.plugins');
320  return _feeds_feeds_plugins();
321}
322
323/**
324 * Implementation of hook_nodeapi().
325 *
326 * @todo For Drupal 7, revisit static cache based shuttling of values between
327 *   'validate' and 'update'/'insert'.
328 */
329function feeds_nodeapi(&$node, $op, $form) {
330
331  // $node looses any changes after 'validate' stage (see node_form_validate()).
332  // Keep a copy of title and feeds array between 'validate' and subsequent
333  // stages. This allows for automatically populating the title of the node form
334  // and modifying the $form['feeds'] array on node validation just like on the
335  // standalone form.
336  static $last_title;
337  static $node_feeds;
338
339  // Break out node processor related nodeapi functionality.
340  _feeds_nodeapi_node_processor($node, $op);
341
342  if ($importer_id = feeds_get_importer_id($node->type)) {
343    switch ($op) {
344      case 'validate':
345        // On validation stage we are working with a FeedsSource object that is
346        // not tied to a nid - when creating a new node there is no
347        // $node->nid at this stage.
348        $source = feeds_source($importer_id);
349
350        // Node module magically moved $form['feeds'] to $node->feeds :P
351        $node_feeds = $node->feeds;
352        $source->configFormValidate($node_feeds);
353
354        // If node title is empty, try to retrieve title from feed.
355        if (trim($node->title) == '') {
356          try {
357            $source->addConfig($node_feeds);
358            if (!$last_title = $source->preview()->getTitle()) {
359              throw new Exception();
360            }
361          }
362          catch (Exception $e) {
363            drupal_set_message($e->getMessage(), 'error');
364            form_set_error('title', t('Could not retrieve title from feed.'));
365          }
366        }
367        break;
368      case 'presave':
369        if (!empty($last_title)) {
370          $node->title = $last_title;
371        }
372        $last_title = NULL;
373        break;
374      case 'insert':
375      case 'update':
376        // A node may not have been validated, make sure $node_feeds is present.
377        if (empty($node_feeds)) {
378          // If $node->feeds is empty here, nodes are being programatically
379          // created in some fashion without Feeds stuff being added.
380          if (empty($node->feeds)) {
381            return;
382          }
383          $node_feeds = $node->feeds;
384        }
385        // Add configuration to feed source and save.
386        $source = feeds_source($importer_id, $node->nid);
387        $source->addConfig($node_feeds);
388        $source->save();
389
390        // Refresh feed if import on create is selected and suppress_import is
391        // not set.
392        if ($op == 'insert' && feeds_importer($importer_id)->config['import_on_create'] && !isset($node_feeds['suppress_import'])) {
393          feeds_batch_set(t('Importing'), 'import', $importer_id, $node->nid);
394        }
395        // Add source to schedule, make sure importer is scheduled, too.
396        if ($op == 'insert') {
397          $source->schedule();
398          $source->importer->schedule();
399        }
400        $node_feeds = NULL;
401        break;
402      case 'delete':
403        $source = feeds_source($importer_id, $node->nid);
404        if (!empty($source->importer->processor->config['delete_with_source'])) {
405          feeds_batch_set(t('Deleting'), 'clear', $importer_id, $node->nid);
406        }
407        // Remove attached source.
408        $source->delete();
409        break;
410    }
411  }
412}
413
414/**
415 * Handles FeedsNodeProcessor specific nodeapi operations.
416 */
417function _feeds_nodeapi_node_processor($node, $op) {
418  switch ($op) {
419    case 'load':
420      if ($result = db_fetch_object(db_query("SELECT imported, guid, url, feed_nid FROM {feeds_node_item} WHERE nid = %d", $node->nid))) {
421        $node->feeds_node_item = $result;
422      }
423      break;
424    case 'insert':
425      if (isset($node->feeds_node_item)) {
426        $node->feeds_node_item->nid = $node->nid;
427        drupal_write_record('feeds_node_item', $node->feeds_node_item);
428      }
429      break;
430    case 'update':
431      if (isset($node->feeds_node_item)) {
432        $node->feeds_node_item->nid = $node->nid;
433        drupal_write_record('feeds_node_item', $node->feeds_node_item, 'nid');
434      }
435      break;
436    case 'delete':
437      db_query("DELETE FROM {feeds_node_item} WHERE nid = %d", $node->nid);
438      break;
439  }
440}
441
442/**
443 * Implementation of hook_taxonomy().
444 */
445function feeds_taxonomy($op = NULL, $type = NULL, $term = NULL) {
446  if ($type == 'term' && !empty($term['tid'])) {
447    switch ($op) {
448      case 'delete':
449        db_query("DELETE FROM {feeds_term_item} WHERE tid = %d", $term['tid']);
450        break;
451      case 'update':
452        if (isset($term['feeds_term_item'])) {
453          db_query("DELETE FROM {feeds_term_item} WHERE tid = %d", $term['tid']);
454        }
455      case 'insert':
456        if (isset($term['feeds_term_item'])) {
457          $term['feeds_term_item']['tid'] = $term['tid'];
458          drupal_write_record('feeds_term_item', $term['feeds_term_item']);
459        }
460        break;
461    }
462  }
463}
464
465/**
466 * Implements hook_form_alter().
467 */
468function feeds_form_alter(&$form, $form_state, $form_id) {
469  if (isset($form['#node']->type) && $form['#node']->type . '_node_form' == $form_id) {
470    if ($importer_id = feeds_get_importer_id($form['#node']->type)) {
471      // Set title to not required, try to retrieve it from feed.
472      if (isset($form['title'])) {
473        $form['title']['#required'] = FALSE;
474      }
475
476      // Enable uploads.
477      $form['#attributes']['enctype'] = 'multipart/form-data';
478
479      // Build form.
480      $source = feeds_source($importer_id, empty($form['#node']->nid) ? 0 : $form['#node']->nid);
481      $form['feeds'] = array(
482        '#type' => 'fieldset',
483        '#title' => t('Feed'),
484        '#tree' => TRUE,
485        '#weight' => 0,
486      );
487      $form['feeds'] += $source->configForm($form_state);
488      $form['#feed_id'] = $importer_id;
489    }
490  }
491}
492
493/**
494 * Implements hook_content_extra_fields().
495 */
496function feeds_content_extra_fields($type) {
497  $extras = array();
498  if (feeds_get_importer_id($type)) {
499    $extras['feeds'] = array(
500      'label' => t('Feed'),
501      'description' => t('Feeds module form elements'),
502      'weight' => 0,
503    );
504  }
505  return $extras;
506}
507
508/**
509 * @}
510 */
511
512/**
513 * @defgroup batch Batch functions
514 */
515
516/**
517 * Batch helper.
518 *
519 * @param $title
520 *   Title to show to user when executing batch.
521 * @param $method
522 *   Method to execute on importer; one of 'import', 'clear' or 'expire'.
523 * @param $importer_id
524 *   Identifier of a FeedsImporter object.
525 * @param $feed_nid
526 *   If importer is attached to content type, feed node id identifying the
527 *   source to be imported.
528 */
529function feeds_batch_set($title, $method, $importer_id, $feed_nid = 0) {
530  $batch = array(
531    'title' => $title,
532    'operations' => array(
533      array('feeds_batch', array($method, $importer_id, $feed_nid)),
534    ),
535    'progress_message' => '',
536  );
537  batch_set($batch);
538}
539
540/**
541 * Batch callback.
542 *
543 * @param $method
544 *   Method to execute on importer; one of 'import' or 'clear'.
545 * @param $importer_id
546 *   Identifier of a FeedsImporter object.
547 * @param $feed_nid
548 *   If importer is attached to content type, feed node id identifying the
549 *   source to be imported.
550 * @param $context
551 *   Batch context.
552 */
553function feeds_batch($method, $importer_id, $feed_nid = 0, &$context) {
554  $context['finished'] = 1;
555  try {
556    $context['finished'] = feeds_source($importer_id, $feed_nid)->$method();
557  }
558  catch (Exception $e) {
559    drupal_set_message($e->getMessage(), 'error');
560  }
561}
562
563/**
564 * @}
565 */
566
567/**
568 * @defgroup utility Utility functions
569 * @{
570 */
571
572/**
573 * Loads all importers.
574 *
575 * @param $load_disabled
576 *   Pass TRUE to load all importers, enabled or disabled, pass FALSE to only
577 *   retrieve enabled importers.
578 *
579 * @return
580 *   An array of all feed configurations available.
581 */
582function feeds_importer_load_all($load_disabled = FALSE) {
583  $feeds = array();
584  // This function can get called very early in install process through
585  // menu_router_rebuild(). Do not try to include CTools if not available.
586  if (function_exists('ctools_include')) {
587    ctools_include('export');
588    $configs = ctools_export_load_object('feeds_importer', 'all');
589    foreach ($configs as $config) {
590      if (!empty($config->id) && ($load_disabled || empty($config->disabled))) {
591        $feeds[$config->id] = feeds_importer($config->id);
592      }
593    }
594  }
595  return $feeds;
596}
597
598/**
599 * Gets an array of enabled importer ids.
600 *
601 * @return
602 *   An array where the values contain ids of enabled importers.
603 */
604function feeds_enabled_importers() {
605  return array_keys(_feeds_importer_digest());
606}
607
608/**
609 * Gets an enabled importer configuration by content type.
610 *
611 * @param $content_type
612 *   A node type string.
613 *
614 * @return
615 *   A FeedsImporter id if there is an importer for the given content type,
616 *   FALSE otherwise.
617 */
618function feeds_get_importer_id($content_type) {
619  $importers = array_flip(_feeds_importer_digest());
620  return isset($importers[$content_type]) ? $importers[$content_type] : FALSE;
621}
622
623/**
624 * Helper function for feeds_get_importer_id() and feeds_enabled_importers().
625 */
626function _feeds_importer_digest() {
627  $importers = &ctools_static(__FUNCTION__);
628  if ($importers === NULL) {
629    if ($cache = cache_get(__FUNCTION__)) {
630      $importers = $cache->data;
631    }
632    else {
633      $importers = array();
634      foreach (feeds_importer_load_all() as $importer) {
635        $importers[$importer->id] = isset($importer->config['content_type']) ? $importer->config['content_type'] : '';
636      }
637      cache_set(__FUNCTION__, $importers);
638    }
639  }
640  return $importers;
641}
642
643/**
644 * Resets importer caches. Call when enabling/disabling importers.
645 */
646function feeds_cache_clear($rebuild_menu = TRUE) {
647  cache_clear_all('_feeds_importer_digest', 'cache');
648  ctools_static_reset('_feeds_importer_digest');
649  ctools_include('export');
650  ctools_export_load_object_reset('feeds_importer');
651  node_get_types('types', NULL, TRUE);
652  if ($rebuild_menu) {
653    menu_rebuild();
654  }
655}
656
657/**
658 * Exports a FeedsImporter configuration to code.
659 */
660function feeds_export($importer_id, $indent = '') {
661  ctools_include('export');
662  $result = ctools_export_load_object('feeds_importer', 'names', array('id' => $importer_id));
663  if (isset($result[$importer_id])) {
664    return ctools_export_object('feeds_importer', $result[$importer_id], $indent);
665  }
666}
667
668/**
669 * Logs to a file like /mytmp/feeds_my_domain_org.log in temporary directory.
670 */
671function feeds_dbg($msg) {
672  if (variable_get('feeds_debug', FALSE)) {
673    if (!is_string($msg)) {
674      $msg = var_export($msg, TRUE);
675    }
676    $filename = trim(str_replace('/', '_', $_SERVER['HTTP_HOST'] . base_path()), '_');
677    $handle = fopen(file_directory_temp() ."/feeds_$filename.log", 'a');
678    fwrite($handle, date('c') ."\t$msg\n");
679    fclose($handle);
680  }
681}
682
683/**
684 * @}
685 */
686
687/**
688 * @defgroup instantiators Instantiators
689 * @{
690 */
691
692/**
693 * Gets an importer instance.
694 *
695 * @param $id
696 *   The unique id of the importer object.
697 *
698 * @return
699 *   A FeedsImporter object or an object of a class defined by the Drupal
700 *   variable 'feeds_importer_class'. There is only one importer object
701 *   per $id system-wide.
702 */
703function feeds_importer($id) {
704  feeds_include('FeedsImporter');
705  return FeedsConfigurable::instance(variable_get('feeds_importer_class', 'FeedsImporter'), $id);
706}
707
708/**
709 * Gets an instance of a source object.
710 *
711 * @param $importer_id
712 *   A FeedsImporter id.
713 * @param $feed_nid
714 *   The node id of a feed node if the source is attached to a feed node.
715 *
716 * @return
717 *   A FeedsSource object or an object of a class defiend by the Drupal
718 *   variable 'source_class'.
719 */
720function feeds_source($importer_id, $feed_nid = 0) {
721  feeds_include('FeedsImporter');
722  return FeedsSource::instance($importer_id, $feed_nid);
723}
724
725/**
726 * @}
727 */
728
729/**
730 * @defgroup plugins Plugin functions
731 * @{
732 *
733 * @todo Encapsulate this in a FeedsPluginHandler class, move it to includes/
734 * and only load it if we're manipulating plugins.
735 */
736
737/**
738 * Gets all available plugins. Does not list hidden plugins.
739 *
740 * @return
741 *   An array where the keys are the plugin keys and the values
742 *   are the plugin info arrays as defined in hook_feeds_plugins().
743 */
744function feeds_get_plugins() {
745  ctools_include('plugins');
746  $plugins = ctools_get_plugins('feeds', 'plugins');
747
748  $result = array();
749  foreach ($plugins as $key => $info) {
750    if (!empty($info['hidden'])) {
751      continue;
752    }
753    $result[$key] = $info;
754  }
755
756  // Sort plugins by name and return.
757  uasort($result, 'feeds_plugin_compare');
758  return $result;
759}
760
761/**
762 * Sort callback for feeds_get_plugins().
763 */
764function feeds_plugin_compare($a, $b) {
765  return strcasecmp($a['name'], $b['name']);
766}
767
768/**
769 * Gets all available plugins of a particular type.
770 *
771 * @param $type
772 *   'fetcher', 'parser' or 'processor'
773 */
774function feeds_get_plugins_by_type($type) {
775  $plugins = feeds_get_plugins();
776
777  $result = array();
778  foreach ($plugins as $key => $info) {
779    if ($type == feeds_plugin_type($key)) {
780      $result[$key] = $info;
781    }
782  }
783  return $result;
784}
785
786/**
787 * Gets an instance of a class for a given plugin and id.
788 *
789 * @param $plugin
790 *   A string that is the key of the plugin to load.
791 * @param $id
792 *   A string that is the id of the object.
793 *
794 * @return
795 *   A FeedsPlugin object.
796 *
797 * @throws Exception
798 *   If plugin can't be instantiated.
799 */
800function feeds_plugin_instance($plugin, $id) {
801  feeds_include('FeedsImporter');
802  ctools_include('plugins');
803  if ($class = ctools_plugin_load_class('feeds', 'plugins', $plugin, 'handler')) {
804    return FeedsConfigurable::instance($class, $id);
805  }
806  $args = array( '%plugin' => $plugin, '@id' => $id);
807  if (user_access('administer feeds')) {
808    $args['@link'] = url('admin/build/feeds/edit/' . $id);
809    drupal_set_message(t('Missing Feeds plugin %plugin. See <a href="@link">@id</a>. Check whether all required libraries and modules are installed properly.', $args), 'warning', FALSE);
810  }
811  else {
812    drupal_set_message(t('Missing Feeds plugin %plugin. Please contact your site administrator.', $args), 'warning', FALSE);
813  }
814  $class = ctools_plugin_load_class('feeds', 'plugins', 'FeedsMissingPlugin', 'handler');
815  return FeedsConfigurable::instance($class, $id);
816}
817
818/**
819 * Determines whether given plugin is derived from given base plugin.
820 *
821 * @param $plugin_key
822 *   String that identifies a Feeds plugin key.
823 * @param $parent_plugin
824 *   String that identifies a Feeds plugin key to be tested against.
825 *
826 * @return
827 *   TRUE if $parent_plugin is directly *or indirectly* a parent of $plugin,
828 *   FALSE otherwise.
829 */
830function feeds_plugin_child($plugin_key, $parent_plugin) {
831  ctools_include('plugins');
832  $plugins = ctools_get_plugins('feeds', 'plugins');
833  $info = $plugins[$plugin_key];
834
835  if (empty($info['handler']['parent'])) {
836    return FALSE;
837  }
838  elseif ($info['handler']['parent'] == $parent_plugin) {
839    return TRUE;
840  }
841  else {
842    return feeds_plugin_child($info['handler']['parent'], $parent_plugin);
843  }
844}
845
846/**
847 * Determines the type of a plugin.
848 *
849 * @param $plugin_key
850 *   String that identifies a Feeds plugin key.
851 *
852 * @return
853 *   One of the following values:
854 *   'fetcher' if the plugin is a fetcher
855 *   'parser' if the plugin is a parser
856 *   'processor' if the plugin is a processor
857 *   FALSE otherwise.
858 */
859function feeds_plugin_type($plugin_key) {
860  if (feeds_plugin_child($plugin_key, 'FeedsFetcher')) {
861    return 'fetcher';
862  }
863  elseif (feeds_plugin_child($plugin_key, 'FeedsParser')) {
864    return 'parser';
865  }
866  elseif (feeds_plugin_child($plugin_key, 'FeedsProcessor')) {
867    return 'processor';
868  }
869  return FALSE;
870}
871
872/**
873 * @}
874 */
875
876/**
877 * @defgroup include Funtions for loading libraries
878 * @{
879 */
880
881/**
882 * Includes a feeds module include file.
883 *
884 * @param $file
885 *   The filename without the .inc extension.
886 * @param $directory
887 *   The directory to include the file from. Do not include files from libraries
888 *   directory. Use feeds_include_library() instead
889 */
890function feeds_include($file, $directory = 'includes') {
891  static $included = array();
892  if (!isset($included[$file])) {
893    require './'. drupal_get_path('module', 'feeds') ."/$directory/$file.inc";
894  }
895  $included[$file] = TRUE;
896}
897
898/**
899 * Includes a library file.
900 *
901 * @param $file
902 *   The filename to load from.
903 * @param $library
904 *   The name of the library. If libraries module is installed,
905 *   feeds_include_library() will look for libraries with this name managed by
906 *   libraries module.
907 */
908function feeds_include_library($file, $library) {
909  static $included = array();
910  if (!isset($included[$file])) {
911    // Try first whether libraries module is present and load the file from
912    // there. If this fails, require the library from the local path.
913    if (module_exists('libraries') && file_exists(libraries_get_path($library) ."/$file")) {
914      require libraries_get_path($library) ."/$file";
915    }
916    else {
917      require './' . drupal_get_path('module', 'feeds') . "/libraries/$file";
918    }
919  }
920  $included[$file] = TRUE;
921}
922
923/**
924 * Checks whether a library is present.
925 *
926 * @param $file
927 *   The filename to load from.
928 * @param $library
929 *   The name of the library. If libraries module is installed,
930 *   feeds_library_exists() will look for libraries with this name managed by
931 *   libraries module.
932 */
933function feeds_library_exists($file, $library) {
934  if (module_exists('libraries') && file_exists(libraries_get_path($library) ."/$file")) {
935    return TRUE;
936  }
937  elseif (file_exists('./' . drupal_get_path('module', 'feeds') . "/libraries/$file")) {
938    return TRUE;
939  }
940  return FALSE;
941}
942
943/**
944 * @}
945 */
946
947/**
948 * Copy of valid_url() that supports the webcal scheme.
949 *
950 * @see valid_url().
951 *
952 * @todo Replace with valid_url() when http://drupal.org/node/295021 is fixed.
953 */
954function feeds_valid_url($url, $absolute = FALSE) {
955  if ($absolute) {
956    return (bool) preg_match("
957      /^                                                      # Start at the beginning of the text
958      (?:ftp|https?|feed|webcal):\/\/                         # Look for ftp, http, https, feed or webcal schemes
959      (?:                                                     # Userinfo (optional) which is typically
960        (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*      # a username or a username and password
961        (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@          # combination
962      )?
963      (?:
964        (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                        # A domain name or a IPv4 address
965        |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])         # or a well formed IPv6 address
966      )
967      (?::[0-9]+)?                                            # Server port number (optional)
968      (?:[\/|\?]
969        (?:[|\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})   # The path and query (optional)
970      *)?
971    $/xi", $url);
972  }
973  else {
974    return (bool) preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url);
975  }
976}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.