1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180 |
- <?php
- /**
- * @file
- * Feeds - basic API functions and hook implementations.
- */
- // Common request time, use as point of reference and to avoid calls to time().
- 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.
- define('FEEDS_EXPORT_NONE', 0x0);
- // Status of batched operations.
- define('FEEDS_BATCH_COMPLETE', 1.0);
- define('FEEDS_BATCH_ACTIVE', 0.0);
- /**
- * @defgroup hooks Hook and callback implementations
- * @{
- */
- /**
- * Implements hook_hook_info().
- */
- function feeds_hook_info() {
- $hooks = array(
- 'feeds_after_parse',
- 'feeds_after_import',
- 'feeds_after_clear',
- 'feeds_processor_targets_alter',
- 'feeds_parser_sources_alter',
- );
- return array_fill_keys($hooks, array('group' => 'feeds'));
- }
- /**
- * Implements hook_cron().
- */
- function feeds_cron() {
- if ($importers = feeds_reschedule()) {
- foreach ($importers as $id) {
- feeds_importer($id)->schedule();
- $rows = db_query("SELECT feed_nid FROM {feeds_source} WHERE id = :id", array(':id' => $id));
- foreach ($rows as $row) {
- feeds_source($id, $row->feed_nid)->schedule();
- }
- }
- feeds_reschedule(FALSE);
- }
- // Expire old log entries.
- db_delete('feeds_log')
- ->condition('request_time', REQUEST_TIME - 604800, '<')
- ->execute();
- }
- /**
- * 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_importer_expire'] = array(
- 'queue name' => 'feeds_importer_expire',
- );
- $info['feeds_push_unsubscribe'] = array(
- 'queue name' => 'feeds_push_unsubscribe',
- );
- return $info;
- }
- /**
- * Implements hook_cron_queue_info().
- */
- function feeds_cron_queue_info() {
- $queues = array();
- $queues['feeds_source_import'] = array(
- 'worker callback' => 'feeds_source_import',
- 'time' => 15,
- );
- $queues['feeds_source_clear'] = array(
- 'worker callback' => 'feeds_source_clear',
- 'time' => 15,
- );
- $queues['feeds_importer_expire'] = array(
- 'worker callback' => 'feeds_importer_expire',
- 'time' => 15,
- );
- $queues['feeds_push_unsubscribe'] = array(
- 'worker callback' => 'feeds_push_unsubscribe',
- 'time' => 15,
- );
- return $queues;
- }
- /**
- * Scheduler callback for importing from a source.
- */
- function feeds_source_import($job) {
- $source = feeds_source($job['type'], $job['id']);
- try {
- $source->existing()->import();
- }
- catch (FeedsNotExistingException $e) {
- // Do nothing.
- }
- catch (Exception $e) {
- $source->log('import', $e->getMessage(), array(), WATCHDOG_ERROR);
- }
- $source->scheduleImport();
- }
- /**
- * Scheduler callback for deleting all items from a source.
- */
- function feeds_source_clear($job) {
- $source = feeds_source($job['type'], $job['id']);
- try {
- $source->existing()->clear();
- }
- catch (FeedsNotExistingException $e) {
- // Do nothing.
- }
- catch (Exception $e) {
- $source->log('clear', $e->getMessage(), array(), WATCHDOG_ERROR);
- }
- $source->scheduleClear();
- }
- /**
- * Scheduler callback for expiring content.
- */
- function feeds_importer_expire($job) {
- $importer = feeds_importer($job['type']);
- try {
- $importer->existing()->expire();
- }
- catch (FeedsNotExistingException $e) {
- // Do nothing.
- }
- catch (Exception $e) {
- $importer->log('expire', $e->getMessage(), array(), WATCHDOG_ERROR);
- }
- $importer->scheduleExpire();
- }
- /**
- * 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');
- }
- }
- /**
- * Reschedule one or all importers.
- *
- * @param $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
- * TRUE if all importers need rescheduling. FALSE if no rescheduling is
- * required. An array 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;
- }
- elseif (is_string($importer_id) && $reschedule !== TRUE) {
- $reschedule = is_array($reschedule) ? $reschedule : array();
- $reschedule[$importer_id] = $importer_id;
- }
- variable_set('feeds_reschedule', $reschedule);
- if ($reschedule === TRUE) {
- return feeds_enabled_importers();
- }
- 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.')
- ),
- );
- 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.')
- );
- }
- return $perms;
- }
- /**
- * Implements hook_forms().
- *
- * Declare form callbacks for all known classes derived from FeedsConfigurable.
- */
- function feeds_forms() {
- $forms = array();
- $forms['FeedsImporter_feeds_form']['callback'] = 'feeds_form';
- $plugins = FeedsPlugin::all();
- foreach ($plugins as $plugin) {
- $forms[$plugin['handler']['class'] . '_feeds_form']['callback'] = 'feeds_form';
- }
- return $forms;
- }
- /**
- * Implements hook_menu().
- */
- function feeds_menu() {
- $items = array();
- $items['import'] = array(
- 'title' => 'Import',
- 'page callback' => 'feeds_page',
- 'access callback' => 'feeds_page_access',
- 'file' => 'feeds.pages.inc',
- );
- $items['import/%'] = 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',
- );
- $items['import/%/import'] = array(
- 'title' => 'Import',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
- $items['import/%/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,
- );
- $items['import/%/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,
- );
- $items['import/%/template'] = array(
- '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.
- foreach (feeds_importer_load_all() as $importer) {
- $items += $importer->fetcher->menuItem();
- }
- return $items;
- }
- /**
- * Menu loader callback.
- */
- function feeds_importer_load($id) {
- return feeds_importer($id);
- }
- /**
- * Title callback.
- */
- function feeds_importer_title($id) {
- $importer = feeds_importer($id);
- return $importer->config['name'];
- }
- /**
- * Implements hook_theme().
- */
- function feeds_theme() {
- return array(
- 'feeds_upload' => array(
- 'file' => 'feeds.pages.inc',
- 'render element' => 'element',
- ),
- 'feeds_source_status' => array(
- 'file' => 'feeds.pages.inc',
- 'variables' => array(
- 'progress_importing' => NULL,
- 'progress_clearing' => NULL,
- 'imported' => NULL,
- 'count' => NULL,
- ),
- ),
- );
- }
- /**
- * Menu access callback.
- *
- * @param $action
- * The action to be performed. Possible values are:
- * - import
- * - clear
- * - unlock
- * @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;
- }
- if (is_string($param)) {
- $importer_id = $param;
- }
- elseif ($param->type) {
- $importer_id = feeds_get_importer_id($param->type);
- }
- // 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")) {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- * Menu access callback.
- */
- function feeds_page_access() {
- if (user_access('administer feeds')) {
- return TRUE;
- }
- foreach (feeds_enabled_importers() as $id) {
- if (user_access("import $id feeds")) {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- * Implements hook_exit().
- */
- function feeds_exit() {
- // 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']);
- }
- if (drupal_static('feeds_log_error', FALSE)) {
- watchdog('feeds', 'Feeds reported errors, visit the Feeds log for details.', array(), WATCHDOG_ERROR, 'admin/reports/dblog/feeds');
- }
- }
- /**
- * Implements hook_views_api().
- */
- function feeds_views_api() {
- return array(
- 'api' => 3,
- 'path' => drupal_get_path('module', 'feeds') . '/views',
- );
- }
- /**
- * Implements hook_ctools_plugin_api().
- */
- function feeds_ctools_plugin_api($owner, $api) {
- if ($owner == 'feeds' && $api == 'plugins') {
- return array('version' => 1);
- }
- }
- /**
- * Implements hook_ctools_plugin_type().
- */
- function feeds_ctools_plugin_type() {
- return array(
- 'plugins' => array(
- 'cache' => TRUE,
- 'use hooks' => TRUE,
- 'classes' => array('handler'),
- ),
- );
- }
- /**
- * Implements hook_feeds_plugins().
- */
- function feeds_feeds_plugins() {
- module_load_include('inc', 'feeds', 'feeds.plugins');
- return _feeds_feeds_plugins();
- }
- /**
- * 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.
- */
- 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();
- }
- /**
- * 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');
- // 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);
- // 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);
- // If node title is empty, try to retrieve title from feed.
- if (trim($node->title) == '') {
- try {
- $source->addConfig($last_feeds);
- if (!$last_title = $source->preview()->title) {
- throw new Exception();
- }
- }
- catch (Exception $e) {
- drupal_set_message($e->getMessage(), 'error');
- form_set_error('title', t('Could not retrieve title from feed.'));
- }
- }
- }
- /**
- * 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;
- }
- /**
- * Implements hook_node_insert().
- */
- function feeds_node_insert($node) {
- // Source attached to node.
- feeds_node_update($node);
- if (isset($node->feeds) && $importer_id = feeds_get_importer_id($node->type)) {
- $source = feeds_source($importer_id, $node->nid);
- // Start import if requested.
- if (feeds_importer($importer_id)->config['import_on_create'] && !isset($node->feeds['suppress_import'])) {
- $source->startImport();
- }
- // Schedule source and importer.
- $source->schedule();
- feeds_importer($importer_id)->schedule();
- }
- }
- /**
- * Implements hook_node_update().
- */
- function feeds_node_update($node) {
- // Source attached to 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) {
- // Source attached to 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)) {
- // Set title to not required, try to retrieve it from feed.
- if (isset($form['title'])) {
- $form['title']['#required'] = FALSE;
- }
- // Enable uploads.
- $form['#attributes']['enctype'] = 'multipart/form-data';
- // Build form.
- $source = feeds_source($importer_id, empty($form['#node']->nid) ? 0 : $form['#node']->nid);
- $form['feeds'] = array(
- '#type' => 'fieldset',
- '#title' => t('Feed'),
- '#tree' => TRUE,
- '#weight' => 0,
- );
- $form['feeds'] += $source->configForm($form_state);
- $form['#feed_id'] = $importer_id;
- }
- }
- /**
- * 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;
- }
- /**
- * @}
- */
- /**
- * @defgroup utility Utility functions
- * @{
- */
- /**
- * Loads all importers.
- *
- * @param $load_disabled
- * Pass TRUE to load all importers, enabled or disabled, pass FALSE to only
- * retrieve enabled importers.
- *
- * @return
- * An array of all feed configurations available.
- */
- function feeds_importer_load_all($load_disabled = FALSE) {
- $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))) {
- $feeds[$config->id] = feeds_importer($config->id);
- }
- }
- }
- return $feeds;
- }
- /**
- * Gets an array of enabled importer ids.
- *
- * @return
- * An array where the values contain ids of enabled importers.
- */
- function feeds_enabled_importers() {
- return array_keys(_feeds_importer_digest());
- }
- /**
- * Gets an enabled importer configuration by content type.
- *
- * @param $content_type
- * A node type string.
- *
- * @return
- * A FeedsImporter id if there is an importer for the given content type,
- * FALSE otherwise.
- */
- function feeds_get_importer_id($content_type) {
- $importers = array_flip(_feeds_importer_digest());
- return isset($importers[$content_type]) ? $importers[$content_type] : FALSE;
- }
- /**
- * Helper function for feeds_get_importer_id() and feeds_enabled_importers().
- */
- function _feeds_importer_digest() {
- $importers = &drupal_static(__FUNCTION__);
- if ($importers === NULL) {
- if ($cache = cache_get(__FUNCTION__)) {
- $importers = $cache->data;
- }
- else {
- $importers = array();
- foreach (feeds_importer_load_all() as $importer) {
- $importers[$importer->id] = isset($importer->config['content_type']) ? $importer->config['content_type'] : '';
- }
- cache_set(__FUNCTION__, $importers);
- }
- }
- return $importers;
- }
- /**
- * Resets importer caches. Call when enabling/disabling importers.
- */
- function feeds_cache_clear($rebuild_menu = TRUE) {
- cache_clear_all('_feeds_importer_digest', 'cache');
- drupal_static_reset('_feeds_importer_digest');
- ctools_include('export');
- ctools_export_load_object_reset('feeds_importer');
- drupal_static_reset('_node_types_build');
- if ($rebuild_menu) {
- menu_rebuild();
- }
- }
- /**
- * Exports a FeedsImporter configuration to code.
- */
- function feeds_export($importer_id, $indent = '') {
- ctools_include('export');
- $result = ctools_export_load_object('feeds_importer', 'names', array('id' => $importer_id));
- if (isset($result[$importer_id])) {
- return ctools_export_object('feeds_importer', $result[$importer_id], $indent);
- }
- }
- /**
- * Logs to a file like /tmp/feeds_my_domain_org.log in temporary directory.
- */
- function feeds_dbg($msg) {
- if (variable_get('feeds_debug', FALSE)) {
- if (!is_string($msg)) {
- $msg = var_export($msg, TRUE);
- }
- $filename = trim(str_replace('/', '_', $_SERVER['HTTP_HOST'] . base_path()), '_');
- $handle = fopen("temporary://feeds_$filename.log", 'a');
- fwrite($handle, gmdate('c') . "\t$msg\n");
- fclose($handle);
- }
- }
- /**
- * Writes to feeds log.
- */
- function feeds_log($importer_id, $feed_nid, $type, $message, $variables = array(), $severity = WATCHDOG_NOTICE) {
- if ($severity < WATCHDOG_NOTICE) {
- $error = &drupal_static('feeds_log_error', FALSE);
- $error = TRUE;
- }
- db_insert('feeds_log')
- ->fields(array(
- 'id' => $importer_id,
- 'feed_nid' => $feed_nid,
- 'log_time' => time(),
- 'request_time' => REQUEST_TIME,
- 'type' => $type,
- 'message' => $message,
- 'variables' => serialize($variables),
- 'severity' => $severity,
- ))
- ->execute();
- }
- /**
- * Loads an item info object.
- *
- * Example usage:
- *
- * $info = feeds_item_info_load('node', $node->nid);
- */
- function feeds_item_info_load($entity_type, $entity_id) {
- return db_select('feeds_item')
- ->fields('feeds_item')
- ->condition('entity_type', $entity_type)
- ->condition('entity_id', $entity_id)
- ->execute()
- ->fetchObject();
- }
- /**
- * Inserts an item info object into the feeds_item table.
- */
- function feeds_item_info_insert($entity, $entity_id) {
- if (isset($entity->feeds_item)) {
- $entity->feeds_item->entity_id = $entity_id;
- drupal_write_record('feeds_item', $entity->feeds_item);
- }
- }
- /**
- * Inserts or updates an item info object in the feeds_item table.
- */
- function feeds_item_info_save($entity, $entity_id) {
- if (isset($entity->feeds_item)) {
- $entity->feeds_item->entity_id = $entity_id;
- if (feeds_item_info_load($entity->feeds_item->entity_type, $entity_id)) {
- drupal_write_record('feeds_item', $entity->feeds_item, array('entity_type', 'entity_id'));
- }
- else {
- feeds_item_info_insert($entity, $entity_id);
- }
- }
- }
- /**
- * @}
- */
- /**
- * @defgroup instantiators Instantiators
- * @{
- */
- /**
- * Gets an importer instance.
- *
- * @param $id
- * The unique id of the importer object.
- *
- * @return
- * A FeedsImporter object or an object of a class defined by the Drupal
- * variable 'feeds_importer_class'. There is only one importer object
- * per $id system-wide.
- */
- function feeds_importer($id) {
- return FeedsConfigurable::instance(variable_get('feeds_importer_class', 'FeedsImporter'), $id);
- }
- /**
- * Gets an instance of a source object.
- *
- * @param $importer_id
- * A FeedsImporter id.
- * @param $feed_nid
- * The node id of a feed node if the source is attached to a feed node.
- *
- * @return
- * A FeedsSource object or an object of a class defiend by the Drupal
- * variable 'source_class'.
- */
- function feeds_source($importer_id, $feed_nid = 0) {
- return FeedsSource::instance($importer_id, $feed_nid);
- }
- /**
- * Gets an instance of a class for a given plugin and id.
- *
- * @param $plugin
- * A string that is the key of the plugin to load.
- * @param $id
- * A string that is the id of the object.
- *
- * @return
- * A FeedsPlugin object.
- *
- * @throws Exception
- * If plugin can't be instantiated.
- */
- function feeds_plugin($plugin, $id) {
- ctools_include('plugins');
- if ($class = ctools_plugin_load_class('feeds', 'plugins', $plugin, 'handler')) {
- return FeedsConfigurable::instance($class, $id);
- }
- $args = array('%plugin' => $plugin, '@id' => $id);
- if (user_access('administer feeds')) {
- $args['@link'] = url('admin/structure/feeds/' . $id);
- 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);
- }
- else {
- drupal_set_message(t('Missing Feeds plugin %plugin. Please contact your site administrator.', $args), 'warning', FALSE);
- }
- $class = ctools_plugin_load_class('feeds', 'plugins', 'FeedsMissingPlugin', 'handler');
- return FeedsConfigurable::instance($class, $id);
- }
- /**
- * @}
- */
- /**
- * @defgroup include Funtions for loading libraries
- * @{
- */
- /**
- * Includes a library file.
- *
- * @param $file
- * The filename to load from.
- * @param $library
- * The name of the library. If libraries module is installed,
- * feeds_include_library() will look for libraries with this name managed by
- * libraries module.
- */
- function feeds_include_library($file, $library) {
- static $included = array();
- static $ignore_deprecated = array('simplepie');
- if (!isset($included[$file])) {
- // Disable deprecated warning for libraries known for throwing them
- if (in_array($library, $ignore_deprecated)) {
- $level = error_reporting();
- // We can safely use E_DEPRECATED since Drupal 7 requires PHP 5.3+
- error_reporting($level ^ E_DEPRECATED ^ E_STRICT);
- }
- $library_dir = variable_get('feeds_library_dir', FALSE);
- $feeds_library_path = DRUPAL_ROOT . '/' . drupal_get_path('module', 'feeds') . "/libraries/$file";
- // Try first whether libraries module is present and load the file from
- // there. If this fails, require the library from the local path.
- if (module_exists('libraries') && file_exists(libraries_get_path($library) . "/$file")) {
- require libraries_get_path($library) . "/$file";
- $included[$file] = TRUE;
- }
- elseif ($library_dir && file_exists("$library_dir/$library/$file")) {
- require "$library_dir/$library/$file";
- $included[$file] = TRUE;
- }
- elseif (file_exists($feeds_library_path)) {
- // @todo: Throws "Deprecated function: Assigning the return value of new
- // by reference is deprecated."
- require $feeds_library_path;
- $included[$file] = TRUE;
- }
- // Restore error reporting level
- if (isset($level)) {
- error_reporting($level);
- }
- }
- if (isset($included[$file])) {
- return TRUE;
- }
- return FALSE;
- }
- /**
- * Checks whether a library is present.
- *
- * @param $file
- * The filename to load from.
- * @param $library
- * The name of the library. If libraries module is installed,
- * feeds_library_exists() will look for libraries with this name managed by
- * libraries module.
- */
- function feeds_library_exists($file, $library) {
- if (module_exists('libraries') && file_exists(libraries_get_path($library) . "/$file")) {
- return TRUE;
- }
- elseif (file_exists(DRUPAL_ROOT . '/' . drupal_get_path('module', 'feeds') . "/libraries/$file")) {
- return TRUE;
- }
- elseif ($library_dir = variable_get('feeds_library_dir', FALSE)) {
- if (file_exists("$library_dir/$library/$file")) {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- * Checks whether simplepie exists.
- */
- function feeds_simplepie_exists() {
- return (feeds_library_exists('simplepie.compiled.php', 'simplepie') ||
- feeds_library_exists('simplepie.mini.php', 'simplepie') ||
- feeds_library_exists('simplepie.inc', 'simplepie')
- );
- }
- /**
- * Includes the simplepie library.
- */
- function feeds_include_simplepie() {
- $files = array('simplepie.mini.php', 'simplepie.compiled.php', 'simplepie.inc');
- foreach ($files as $file) {
- if (feeds_include_library($file, 'simplepie')) {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- * @deprecated
- *
- * Simplified drupal_alter().
- *
- * - None of that 'multiple parameters by ref' crazyness.
- * - Don't use module_implements() to allow hot including on behalf
- * implementations (see mappers/).
- *
- * @todo This needs to be removed and drupal_alter() used. This is crazy dumb.
- */
- function feeds_alter($type, &$data) {
- $args = array(&$data);
- $additional_args = func_get_args();
- array_shift($additional_args);
- array_shift($additional_args);
- $args = array_merge($args, $additional_args);
- $hook = $type . '_alter';
- foreach (module_list() as $module) {
- if (module_hook($module, $hook)) {
- call_user_func_array($module . '_' . $hook, $args);
- }
- }
- }
- /**
- * @}
- */
- /**
- * Copy of valid_url() that supports the webcal scheme.
- *
- * @see valid_url().
- *
- * @todo Replace with valid_url() when http://drupal.org/node/295021 is fixed.
- */
- function feeds_valid_url($url, $absolute = FALSE) {
- if ($absolute) {
- return (bool) preg_match("
- /^ # Start at the beginning of the text
- (?:ftp|https?|feed|webcal):\/\/ # Look for ftp, http, https, feed or webcal schemes
- (?: # Userinfo (optional) which is typically
- (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)* # a username or a username and password
- (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@ # combination
- )?
- (?:
- (?:[a-z0-9\-\.]|%[0-9a-f]{2})+ # A domain name or a IPv4 address
- |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]) # or a well formed IPv6 address
- )
- (?::[0-9]+)? # Server port number (optional)
- (?:[\/|\?]
- (?:[|\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
- *)?
- $/xi", $url);
- }
- else {
- return (bool) preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url);
- }
- }
- /**
- * Registers a feed subscription job for execution on feeds_exit().
- *
- * @param array $job
- * Information about a new job to queue; or if set to NULL (default), leaves
- * the current queued jobs unchanged.
- *
- * @return
- * An array of subscribe jobs to process.
- *
- * @see feeds_exit()
- * @see feeds_get_subscription_jobs()
- */
- function feeds_set_subscription_job(array $job = NULL) {
- $jobs = &drupal_static(__FUNCTION__, array());
- if (isset($job)) {
- $jobs[] = $job;
- }
- return $jobs;
- }
- /**
- * Returns the list of queued jobs to be run.
- *
- * @return
- * An array of subscribe jobs to process.
- *
- * @see feeds_set_subscription_job()
- */
- function feeds_get_subscription_jobs() {
- return feeds_set_subscription_job();
- }
- /**
- * Implements hook_entity_property_info_alter().
- */
- function feeds_entity_property_info_alter(&$info) {
- // Gather entities supported by Feeds processors.
- $processors = FeedsPlugin::byType('processor');
- $supported_entities = array();
- foreach ($processors as $processor) {
- $instance = feeds_plugin($processor['handler']['class'], '__none__');
- if (method_exists($instance, 'entityType')) {
- $supported_entities[] = $instance->entityType();
- }
- }
- // Feeds processors can fake the entity info. Only set the property for
- // defined entities.
- $supported_entities = array_intersect(array_keys($info), $supported_entities);
- foreach ($supported_entities as $entity_type) {
- $info[$entity_type]['properties']['feed_nid'] = array(
- 'label' => 'Feed NID',
- 'type' => 'integer',
- 'description' => t('Nid of the Feed Node that imported this entity.'),
- 'getter callback' => 'feeds_get_feed_nid_entity_callback',
- );
- }
- }
- /**
- * Gets the feed_nid for an entity for use in entity metadata.
- */
- function feeds_get_feed_nid_entity_callback($entity, array $options, $name, $entity_type) {
- list($entity_id, , ) = entity_extract_ids($entity_type, $entity);
- $feed_nid = feeds_get_feed_nid($entity_id, $entity_type);
- if ($feed_nid === FALSE) {
- return NULL;
- }
- return $feed_nid;
- }
|