Newer
Older
Alex Barth
committed
Alex Barth
committed
* Feeds - basic API functions and hook implementations.
*/
// Common request time, use as point of reference and to avoid calls to time().
Alex Barth
committed
define('FEEDS_REQUEST_TIME', time());
// Do not schedule a feed for refresh.
define('FEEDS_SCHEDULE_NEVER', -1);
// Never expire feed items.
define('FEEDS_EXPIRE_NEVER', -1);
// An object that is not persistent. Compare EXPORT_IN_DATABASE, EXPORT_IN_CODE.
Alex Barth
committed
define('FEEDS_EXPORT_NONE', 0x0);
define('FEEDS_BATCH_COMPLETE', 1.0);
define('FEEDS_BATCH_ACTIVE', 0.0);
Alex Barth
committed
/**
Alex Barth
committed
* @{
/**
* Implements hook_hook_info().
*/
function feeds_hook_info() {
$hooks = array(
'feeds_plugins',
'feeds_after_parse',
'feeds_before_import',
'feeds_before_update',
'feeds_presave',
'feeds_after_import',
'feeds_after_clear',
'feeds_processor_targets',
'feeds_processor_targets_alter',
'feeds_parser_sources_alter',
);
return array_fill_keys($hooks, array('group' => 'feeds'));
}
*/
function feeds_cron() {
// Expire old log entries.
db_delete('feeds_log')
->condition('request_time', REQUEST_TIME - 604800, '<')
->execute();
// Find importers that need to be rescheduled.
$importers = feeds_reschedule();
if ($importers) {
// @todo Maybe we should queue this somehow as well. This could be potentially
// very long.
$sources = db_query("SELECT feed_nid, id FROM {feeds_source} WHERE id IN (:ids)", array(':ids' => $importers));
foreach ($sources as $source) {
feeds_source($source->id, $source->feed_nid)->schedule();
}
feeds_reschedule(FALSE);
}
// Sync the files in the cache directory with entries in the cache every now
// and then. By default: every six hours.
$last_check = variable_get('feeds_sync_cache_feeds_http_last_check');
$interval = variable_get('feeds_sync_cache_feeds_http_interval', 21600);
if ($last_check < (REQUEST_TIME - $interval)) {
// Check first if the task isn't already queued.
$queue = DrupalQueue::get('feeds_sync_cache_feeds_http');
if ($queue->numberOfItems() < 1) {
// Queue sync task.
FeedsHTTPCache::getInstance('cache_feeds_http')->startSync();
}
variable_set('feeds_sync_cache_feeds_http_last_check', REQUEST_TIME);
}
Alex Barth
committed
}
/**
* Implements hook_cron_job_scheduler_info().
* Compare queue names with key names in feeds_cron_queue_info().
*/
function feeds_cron_job_scheduler_info() {
$info = array();
$info['feeds_source_import'] = array(
'queue name' => 'feeds_source_import',
);
$info['feeds_source_clear'] = array(
'queue name' => 'feeds_source_clear',
);
$info['feeds_source_expire'] = array(
'queue name' => 'feeds_source_expire',
$info['feeds_push_unsubscribe'] = array(
'queue name' => 'feeds_push_unsubscribe',
);
return $info;
}
/**
* Implements hook_cron_queue_info().
Alex Barth
committed
*/
function feeds_cron_queue_info() {
$queues = array();
Alex Barth
committed
$queues['feeds_source_import'] = array(
'worker callback' => 'feeds_source_import',
klausi
committed
'time' => 60,
Alex Barth
committed
);
$queues['feeds_source_clear'] = array(
'worker callback' => 'feeds_source_clear',
);
$queues['feeds_source_expire'] = array(
'worker callback' => 'feeds_source_expire',
Alex Barth
committed
);
$queues['feeds_push_unsubscribe'] = array(
'worker callback' => 'feeds_push_unsubscribe',
);
$queues['feeds_sync_cache_feeds_http'] = array(
'worker callback' => 'feeds_sync_cache_feeds_http',
);
Alex Barth
committed
return $queues;
Alex Barth
committed
/**
* Scheduler callback for importing from a source.
*/
function feeds_source_import(array $job) {
$source = _feeds_queue_worker_helper($job, 'import');
$source->scheduleImport();
}
/**
* Scheduler callback for deleting all items from a source.
*/
function feeds_source_clear(array $job) {
$source = _feeds_queue_worker_helper($job, 'clear');
Alex Barth
committed
}
/**
* Scheduler callback for expiring content.
*/
function feeds_source_expire(array $job) {
$source = _feeds_queue_worker_helper($job, 'expire');
$source->scheduleExpire();
}
/**
* Executes a method on a feed source.
*
* @param array $job
* The job being run.
* @param string $method
* The method to execute.
*/
function _feeds_queue_worker_helper(array $job, $method) {
$source = feeds_source($job['type'], $job['id']);
Alex Barth
committed
try {
$source->existing()->$method();
Alex Barth
committed
}
catch (FeedsNotExistingException $e) {
// Do nothing.
}
Alex Barth
committed
catch (Exception $e) {
$source->log($method, $e->getMessage(), array(), WATCHDOG_ERROR);
Alex Barth
committed
}
return $source;
/**
* Scheduler callback for syncing the feeds cache directory with the entries in
* the cache.
*/
function feeds_sync_cache_feeds_http(array $job) {
FeedsHTTPCache::getInstance('cache_feeds_http')->sync($job['files']);
}
/**
* Scheduler callback for unsubscribing from PuSH hubs.
*/
function feeds_push_unsubscribe($job) {
$source = feeds_source($job['type'], $job['id']);
$fetcher = feeds_plugin('FeedsHTTPFetcher', $source->importer->id);
$fetcher->unsubscribe($source);
}
/**
* Batch API worker callback. Used by FeedsSource::startBatchAPIJob().
*
* @see FeedsSource::startBatchAPIJob().
*
* @todo Harmonize Job Scheduler API callbacks with Batch API callbacks?
*
* @param $method
* Method to execute on importer; one of 'import' or 'clear'.
* @param $importer_id
* Identifier of a FeedsImporter object.
* @param $feed_nid
* If importer is attached to content type, feed node id identifying the
* source to be imported.
* @param $context
* Batch context.
*/
function feeds_batch($method, $importer_id, $feed_nid = 0, &$context) {
$context['finished'] = FEEDS_BATCH_COMPLETE;
try {
$context['finished'] = feeds_source($importer_id, $feed_nid)->$method();
}
catch (Exception $e) {
drupal_set_message($e->getMessage(), 'error');
}
Alex Barth
committed
}
/**
* Reschedule one or all importers.
*
* @param string $importer_id
* If TRUE, all importers will be rescheduled, if FALSE, no importers will
* be rescheduled, if an importer id, only importer of that id will be
* rescheduled.
*
* @return array
* An list of importers that need rescheduling.
*/
function feeds_reschedule($importer_id = NULL) {
$reschedule = variable_get('feeds_reschedule', FALSE);
if ($importer_id === TRUE || $importer_id === FALSE) {
$reschedule = $importer_id;
Alex Barth
committed
}
elseif (is_string($importer_id) && $reschedule !== TRUE) {
$reschedule = array_filter((array) $reschedule);
$reschedule[$importer_id] = $importer_id;
}
if (isset($importer_id)) {
variable_set('feeds_reschedule', $reschedule);
}
if ($reschedule === TRUE) {
return feeds_enabled_importers();
Alex Barth
committed
}
elseif ($reschedule === FALSE) {
return array();
}
Alex Barth
committed
return $reschedule;
}
* Implements feeds_permission().
function feeds_permission() {
$perms = array(
'administer feeds' => array(
'title' => t('Administer Feeds'),
'description' => t('Create, update, delete importers, execute import and delete tasks on any importer.')
Alex Barth
committed
foreach (feeds_importer_load_all() as $importer) {
$perms["import $importer->id feeds"] = array(
'title' => t('Import @name feeds', array('@name' => $importer->config['name'])),
$perms["clear $importer->id feeds"] = array(
'title' => t('Delete items from @name feeds', array('@name' => $importer->config['name'])),
$perms["unlock $importer->id feeds"] = array(
'title' => t('Unlock imports from @name feeds', array('@name' => $importer->config['name'])),
'description' => t('If a feed importation breaks for some reason, users with this permission can unlock them.')
);
Alex Barth
committed
}
return $perms;
}
/**
*
* Declare form callbacks for all known classes derived from FeedsConfigurable.
Alex Barth
committed
*/
function feeds_forms($form_id, $args) {
// Check if the requested form is a Feeds form.
if (!stripos($form_id, '_feeds_form')) {
return;
}
Alex Barth
committed
$forms = array();
$forms['FeedsImporter_feeds_form']['callback'] = 'feeds_form';
Alex Barth
committed
$plugins = FeedsPlugin::all();
Alex Barth
committed
foreach ($plugins as $plugin) {
$forms[$plugin['handler']['class'] . '_feeds_form']['callback'] = 'feeds_form';
Alex Barth
committed
}
return $forms;
}
/**
Alex Barth
committed
*/
function feeds_menu() {
$items = array();
$items['import'] = array(
'title' => 'Import',
'page callback' => 'feeds_page',
'access callback' => 'feeds_page_access',
'file' => 'feeds.pages.inc',
);
Chris Leppanen
committed
$items['import/%feeds_importer'] = array(
'title callback' => 'feeds_importer_title',
'title arguments' => array(1),
'page callback' => 'drupal_get_form',
'page arguments' => array('feeds_import_form', 1),
'access callback' => 'feeds_access',
'access arguments' => array('import', 1),
'file' => 'feeds.pages.inc',
);
Chris Leppanen
committed
$items['import/%feeds_importer/import'] = array(
'title' => 'Import',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
Chris Leppanen
committed
$items['import/%feeds_importer/delete-items'] = array(
'title' => 'Delete items',
'page callback' => 'drupal_get_form',
'page arguments' => array('feeds_delete_tab_form', 1),
'access callback' => 'feeds_access',
'access arguments' => array('clear', 1),
'file' => 'feeds.pages.inc',
'type' => MENU_LOCAL_TASK,
);
Chris Leppanen
committed
$items['import/%feeds_importer/unlock'] = array(
'title' => 'Unlock',
'page callback' => 'drupal_get_form',
'page arguments' => array('feeds_unlock_tab_form', 1),
'access callback' => 'feeds_access',
'access arguments' => array('unlock', 1),
'file' => 'feeds.pages.inc',
'type' => MENU_LOCAL_TASK,
);
Chris Leppanen
committed
$items['import/%feeds_importer/template'] = array(
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
'page callback' => 'feeds_importer_template',
'page arguments' => array(1),
'access callback' => 'feeds_access',
'access arguments' => array('import', 1),
'file' => 'feeds.pages.inc',
'type' => MENU_CALLBACK,
);
$items['node/%node/import'] = array(
'title' => 'Import',
'page callback' => 'drupal_get_form',
'page arguments' => array('feeds_import_tab_form', 1),
'access callback' => 'feeds_access',
'access arguments' => array('import', 1),
'file' => 'feeds.pages.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 10,
);
$items['node/%node/delete-items'] = array(
'title' => 'Delete items',
'page callback' => 'drupal_get_form',
'page arguments' => array('feeds_delete_tab_form', NULL, 1),
'access callback' => 'feeds_access',
'access arguments' => array('clear', 1),
'file' => 'feeds.pages.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 11,
);
$items['node/%node/unlock'] = array(
'title' => 'Unlock',
'page callback' => 'drupal_get_form',
'page arguments' => array('feeds_unlock_tab_form', NULL, 1),
'access callback' => 'feeds_access',
'access arguments' => array('unlock', 1),
'file' => 'feeds.pages.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 11,
);
// @todo Eliminate this step and thus eliminate clearing menu cache when
// manipulating importers.
Alex Barth
committed
foreach (feeds_importer_load_all() as $importer) {
Alex Barth
committed
}
return $items;
}
/**
* Implements hook_admin_paths().
*/
function feeds_admin_paths() {
$paths = array(
'import' => TRUE,
'import/*' => TRUE,
'node/*/import' => TRUE,
'node/*/delete-items' => TRUE,
'node/*/log' => TRUE,
);
return $paths;
}
Alex Barth
committed
/**
* Menu loader callback.
*/
function feeds_importer_load($id) {
Chris Leppanen
committed
try {
wmostrey
committed
$importer = feeds_importer($id);
if ($importer->doesExist()) {
return $importer;
}
Chris Leppanen
committed
}
catch (InvalidArgumentException $e) {}
return FALSE;
Alex Barth
committed
}
Chris Leppanen
committed
function feeds_importer_title(FeedsImporter $importer) {
Alex Barth
committed
/**
Alex Barth
committed
*/
function feeds_theme() {
return array(
'feeds_upload' => array(
'file' => 'feeds.pages.inc',
Alex Barth
committed
),
Alex Barth
committed
'feeds_source_status' => array(
'file' => 'feeds.pages.inc',
'variables' => array(
'progress_importing' => NULL,
'progress_clearing' => NULL,
'imported' => NULL,
'count' => NULL,
),
),
Alex Barth
committed
);
}
/**
* Menu access callback.
*
* @param $action
* The action to be performed. Possible values are:
* - import
* - clear
Alex Barth
committed
* @param $param
* Node object or FeedsImporter id.
*/
function feeds_access($action, $param) {
if (!in_array($action, array('import', 'clear', 'unlock'))) {
// If $action is not one of the supported actions, we return access denied.
return FALSE;
}
Chris Leppanen
committed
$importer_id = FALSE;
Alex Barth
committed
if (is_string($param)) {
$importer_id = $param;
}
Chris Leppanen
committed
elseif ($param instanceof FeedsImporter) {
$importer_id = $param->id;
}
Alex Barth
committed
elseif ($param->type) {
$importer_id = feeds_get_importer_id($param->type);
Alex Barth
committed
}
// Check for permissions if feed id is present, otherwise return FALSE.
if ($importer_id) {
if (user_access('administer feeds') || user_access("{$action} {$importer_id} feeds")) {
Alex Barth
committed
return TRUE;
}
}
return FALSE;
}
worldfallz
committed
/**
* Access callback to determine if the user can import Feeds importers.
*
* Feeds imports require an additional access check because they are PHP
* code and PHP is more locked down than administer feeds.
*/
function feeds_importer_import_access() {
return user_access('administer feeds') && user_access('use PHP for settings');
}
Alex Barth
committed
/**
* Menu access callback.
*/
function feeds_page_access() {
if (user_access('administer feeds')) {
return TRUE;
}
foreach (feeds_enabled_importers() as $id) {
Alex Barth
committed
return TRUE;
}
}
return FALSE;
}
/**
* Implements hook_exit().
*/
function feeds_exit() {
elliotttf
committed
// Process any pending PuSH subscriptions.
$jobs = feeds_get_subscription_jobs();
foreach ($jobs as $job) {
if (!isset($job['fetcher']) || !isset($job['source'])) {
continue;
}
$job['fetcher']->subscribe($job['source']);
}
stevekessler
committed
watchdog('feeds', 'Feeds reported errors, visit the Feeds log for details.', array(), WATCHDOG_ERROR, l(t('view'), 'admin/reports/feeds'));
Alex Barth
committed
/**
* Implements hook_views_api().
Alex Barth
committed
*/
function feeds_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'feeds') . '/views',
Alex Barth
committed
);
}
/**
* Implements hook_ctools_plugin_api().
Alex Barth
committed
*/
function feeds_ctools_plugin_api($owner, $api) {
if ($owner == 'feeds' && $api == 'plugins') {
return array('version' => 1);
}
}
Alex Barth
committed
/**
* Implements hook_ctools_plugin_type().
Alex Barth
committed
*/
function feeds_ctools_plugin_type() {
Alex Barth
committed
return array(
'plugins' => array(
'cache' => TRUE,
'use hooks' => TRUE,
'classes' => array('handler'),
),
Alex Barth
committed
);
}
Alex Barth
committed
/**
* Implements hook_feeds_plugins().
Alex Barth
committed
*/
function feeds_feeds_plugins() {
module_load_include('inc', 'feeds', 'feeds.plugins');
return _feeds_feeds_plugins();
}
/**
Chris Leppanen
committed
* Gets the feed_nid for a single entity.
*
* @param int $entity_id
* The entity id.
* @param string $entity_type
* The type of entity.
*
* @return int|bool
* The feed_nid of the entity, or FALSE if the entity doesn't belong to a
* feed.
*/
Chris Leppanen
committed
function feeds_get_feed_nid($entity_id, $entity_type) {
return db_query("SELECT feed_nid FROM {feeds_item} WHERE entity_type = :type AND entity_id = :id", array(':type' => $entity_type, ':id' => $entity_id))->fetchField();
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
}
/**
* Implements hook_entity_insert().
*/
function feeds_entity_insert($entity, $type) {
list($id) = entity_extract_ids($type, $entity);
feeds_item_info_insert($entity, $id);
}
/**
* Implements hook_entity_update().
*/
function feeds_entity_update($entity, $type) {
list($id) = entity_extract_ids($type, $entity);
feeds_item_info_save($entity, $id);
}
/**
* Implements hook_entity_delete().
*/
function feeds_entity_delete($entity, $type) {
list($id) = entity_extract_ids($type, $entity);
// Delete any imported items produced by the source.
db_delete('feeds_item')
->condition('entity_type', $type)
->condition('entity_id', $id)
->execute();
}
/**
* Implements hook_node_validate().
*/
function feeds_node_validate($node, $form, &$form_state) {
if (!$importer_id = feeds_get_importer_id($node->type)) {
return;
}
// Keep a copy of the title for subsequent node creation stages.
// @todo: revisit whether $node still looses all of its properties
// between validate and insert stage.
$last_title = &drupal_static('feeds_node_last_title');
$last_feeds = &drupal_static('feeds_node_last_feeds');
Alex Barth
committed
// On validation stage we are working with a FeedsSource object that is
// not tied to a nid - when creating a new node there is no
// $node->nid at this stage.
$source = feeds_source($importer_id);
Alex Barth
committed
Alex Barth
committed
// Node module magically moved $form['feeds'] to $node->feeds :P.
// configFormValidate may modify $last_feed, smuggle it to update/insert stage
// through a static variable.
$last_feeds = $node->feeds;
$source->configFormValidate($last_feeds);
megachriz
committed
// Check if title form element is hidden.
$title_hidden = (isset($form['title']['#access']) && !$form['title']['#access']);
// If the node title is empty and the title form element wasn't hidden, try to
// retrieve the title from the feed.
megachriz
committed
if (isset($node->title) && trim($node->title) == '' && !$title_hidden) {
try {
$source->addConfig($last_feeds);
Alex Barth
committed
if (!$last_title = $source->preview()->title) {
throw new Exception();
}
}
catch (Exception $e) {
drupal_set_message($e->getMessage(), 'error');
Dave Reid
committed
form_set_error('title', t('Could not retrieve title from feed.'));
Alex Barth
committed
}
}
}
Alex Barth
committed
/**
* Implements hook_node_presave().
*/
function feeds_node_presave($node) {
// Populate $node->title and $node->feed from result of validation phase.
$last_title = &drupal_static('feeds_node_last_title');
$last_feeds = &drupal_static('feeds_node_last_feeds');
if (empty($node->title) && !empty($last_title)) {
$node->title = $last_title;
}
if (!empty($last_feeds)) {
$node->feeds = $last_feeds;
}
$last_title = NULL;
$last_feeds = NULL;
megachriz
committed
// Update "changed" value if there was mapped to that.
if (isset($node->feeds_item->node_changed)) {
$node->changed = $node->feeds_item->node_changed;
}
Alex Barth
committed
}
Alex Barth
committed
/**
Alex Barth
committed
*/
function feeds_node_insert($node) {
if (isset($node->feeds) && $importer_id = feeds_get_importer_id($node->type)) {
$source = feeds_source($importer_id, $node->nid);
Alex Barth
committed
// Start import if requested.
if (feeds_importer($importer_id)->config['import_on_create'] && !isset($node->feeds['suppress_import'])) {
Alex Barth
committed
}
// Schedule the source.
Alex Barth
committed
}
}
/**
* Implements hook_node_update().
*/
function feeds_node_update($node) {
if (isset($node->feeds) && $importer_id = feeds_get_importer_id($node->type)) {
$source = feeds_source($importer_id, $node->nid);
$source->addConfig($node->feeds);
$source->save();
}
}
/**
* Implements hook_node_delete().
*/
function feeds_node_delete($node) {
// Make sure we don't leave any orphans behind: Do not use
// feeds_get_importer_id() to determine importer id as the importer may have
// been deleted.
if ($importer_id = db_query("SELECT id FROM {feeds_source} WHERE feed_nid = :nid", array(':nid' => $node->nid))->fetchField()) {
feeds_source($importer_id, $node->nid)->delete();
}
}
* Implements hook_form_BASE_FORM_ID_alter().
*/
function feeds_form_node_form_alter(&$form, $form_state) {
if ($importer_id = feeds_get_importer_id($form['#node']->type)) {
// Enable uploads.
$form['#attributes']['enctype'] = 'multipart/form-data';
// Build form.
$source = feeds_source($importer_id, empty($form['#node']->nid) ? NULL : $form['#node']->nid);
$form['feeds'] = array(
'#type' => 'fieldset',
'#title' => t('Feed'),
'#tree' => TRUE,
Dave Reid
committed
'#weight' => 0,
);
$form['feeds'] += $source->configForm($form_state);
$form['#feed_id'] = $importer_id;
// If the parser has support for delivering a source title, set node title
// to not required and try to retrieve it from the source if the node title
// is left empty by the user.
// @see feeds_node_validate()
if (isset($form['title']) && $source->importer()->parser->providesSourceTitle()) {
$form['title']['#required'] = FALSE;
}
Alex Barth
committed
}
}
Dave Reid
committed
/**
* Implements hook_field_extra_fields().
*/
function feeds_field_extra_fields() {
$extras = array();
foreach (node_type_get_names() as $type => $name) {
if (feeds_get_importer_id($type)) {
$extras['node'][$type]['form']['feeds'] = array(
'label' => t('Feed'),
'description' => t('Feeds module form elements'),
'weight' => 0,
);
}
}
return $extras;
}
megachriz
committed
/**
* Implements hook_features_pipe_COMPONENT_alter() for component "feeds_importer".
*
* Automatically adds dependencies when a Feed importer is selected in Features.
*/
function feeds_features_pipe_feeds_importer_alter(&$pipe, $data, &$export) {
foreach ($data as $importer_id) {
if ($importer = feeds_importer_load($importer_id)) {
$export['dependencies'] = array_merge($export['dependencies'], $importer->dependencies());
}
}
}
Chris Leppanen
committed
/**
* Implements hook_system_info_alter().
*
* Goes through a list of all modules that provide Feeds plugins and makes them
* required if there are any importers using those plugins.
*/
function feeds_system_info_alter(array &$info, $file, $type) {
if ($type !== 'module' || !module_exists($file->name) || !module_hook($file->name, 'feeds_plugins')) {
Chris Leppanen
committed
return;
}
// Don't make Feeds require itself, otherwise you can't disable Feeds until
// all importers are deleted.
if ($file->name === 'feeds' || !function_exists('ctools_include')) {
return;
}
// Get the plugins that belong to the current module.
ctools_include('plugins');
$module_plugins = array();
foreach (ctools_get_plugins('feeds', 'plugins') as $plugin_id => $plugin) {
if ($file->name === $plugin['module']) {
$module_plugins[$plugin_id] = TRUE;
}
}
// Check if any importers are using any plugins from the current module.
foreach (feeds_importer_load_all(TRUE) as $importer) {
// Skip importers that are defined in code and are provided by the current
// module. This ensures that modules that define both an importer and a
// plugin can still be disabled.
if ($importer->export_type == EXPORT_IN_CODE) {
$configs = ctools_export_load_object('feeds_importer', 'names', array($importer->id));
if (isset($configs[$importer->id]) && $configs[$importer->id]->export_module === $file->name) {
continue;
}
}
Chris Leppanen
committed
$configuration = $importer->getConfig();
foreach (array('fetcher', 'parser', 'processor') as $plugin_type) {
$plugin_key = $configuration[$plugin_type]['plugin_key'];
if (isset($module_plugins[$plugin_key])) {
$info['required'] = TRUE;
break 2;
}
}
}
if (empty($info['required'])) {
return;
}
if (module_exists('feeds_ui') && user_access('administer feeds')) {
$info['explanation'] = t('Feeds is currently using this module for one or more <a href="@link">importers</a>', array('@link' => url('admin/structure/feeds')));
Chris Leppanen
committed
}
else {
$info['explanation'] = t('Feeds is currently using this module for one or more importers');
Chris Leppanen
committed
}
}
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
/**
* Implements hook_module_implements_alter().
*/
function feeds_module_implements_alter(array &$implementations, $hook) {
if ($hook === 'feeds_processor_targets_alter') {
// We need two implementations of this hook, so we add one that gets
// called first, and move the normal one to last.
$implementations = array('_feeds' => FALSE) + $implementations;
// Move normal implementation to last.
$group = $implementations['feeds'];
unset($implementations['feeds']);
$implementations['feeds'] = $group;
}
}
/**
* Implements hook_feeds_processor_targets_alter().
*
* @see feeds_feeds_processor_targets()
* @see feeds_feeds_processor_targets_alter()
*/
function _feeds_feeds_processor_targets_alter(array &$targets, $entity_type, $bundle) {
// If hook_feeds_processor_targets() hasn't been called, for instance, by
// older processors, invoke it ourself.
if (!drupal_static('feeds_feeds_processor_targets', FALSE)) {
$targets += module_invoke_all('feeds_processor_targets', $entity_type, $bundle);
}
}
/**
* Implements hook_flush_caches().
*/
function feeds_flush_caches() {
// The update to add the table needs to have run. Taken from
// https://www.drupal.org/node/2511858
include_once DRUPAL_ROOT . '/includes/install.inc';
if (drupal_get_installed_schema_version('feeds') >= 7212) {
return array('cache_feeds_http');
}
return array();
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
/**
* Implements hook_admin_menu_output_build().
*
* Shows available importers in the "Content" section of the admin menu.
* Requires the "admin_menu" module to be enabled.
*/
function feeds_admin_menu_output_build(array &$content) {
// Add new top-level item to the menu.
if (!isset($content['menu'])) {
return;
}
$access = FALSE;
foreach (feeds_enabled_importers() as $importer_id) {
if (user_access('administer feeds') || user_access("import $importer_id feeds")) {
$access = TRUE;
break;
}
}
if (!$access) {
return;
}
$content['menu']['admin/content']['admin/content/feeds_import'] = array(
'#title' => t('Import'),
'#href' => 'import',
);
foreach (feeds_importer_load_all() as $importer) {
$content['menu']['admin/content']['admin/content/feeds_import'][$importer->id] = array(
'#title' => t($importer->config['name']),
'#href' => !empty($importer->config['content_type']) ? 'node/add/' . $importer->config['content_type'] : 'import/' . check_plain($importer->id),
'#access' => user_access('administer feeds') || user_access("import $importer->id feeds"),
);
}
}
/**
* Implements hook_menu_local_tasks_alter().
*
* Adds "Import" link as local action on content overview page.
*/
function feeds_menu_local_tasks_alter(&$data, $router_item, $root_path) {
if ($root_path == 'admin/content') {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_task',
'#link' => array(
'title' => t('Import'),
'href' => 'import',
'localized_options' => array(
'attributes' => array(
'title' => t('Import'),
),
),
),
'#access' => feeds_page_access(),
// Add weight so it appears after the local action "Add content".
'#weight' => 1,
);
}
}
Alex Barth
committed
/**
* @defgroup utility Utility functions
* @{
*/
/**
* Loads all importers.
Alex Barth
committed
*
* @param $load_disabled
* Pass TRUE to load all importers, enabled or disabled, pass FALSE to only
* retrieve enabled importers.
Alex Barth
committed
* @return
* An array of all feed configurations available.
*/
function feeds_importer_load_all($load_disabled = FALSE) {
Alex Barth
committed
$feeds = array();
// This function can get called very early in install process through
// menu_router_rebuild(). Do not try to include CTools if not available.
if (function_exists('ctools_include')) {
ctools_include('export');
$configs = ctools_export_load_object('feeds_importer', 'all');
foreach ($configs as $config) {
if (!empty($config->id) && ($load_disabled || empty($config->disabled))) {
Alex Barth
committed
$feeds[$config->id] = feeds_importer($config->id);
git
committed
uasort($feeds, 'feeds_importer_name_sort');
Alex Barth
committed
return $feeds;
git
committed
/**
* Sorts importers by name.
*
* Callback for uasort().
*
* @param FeedsImporter $a
* The first FeedsImporter for comparison.
* @param FeedsImporter $b
* The second FeedsImporter for comparison.
*
* @return int
* The comparison result for uasort().
*/
function feeds_importer_name_sort(FeedsImporter $a, FeedsImporter $b) {
return strcasecmp($a->config['name'], $b->config['name']);
}