feed_nid = $feed_nid; $this->importer = feeds_importer($importer_id); parent::__construct($importer_id); $this->load(); } /** * Preview = fetch and parse a feed. * * @return * FeedsImportBatch object, fetched and parsed. * * @throws * Throws Exception if an error occurs when fetching or parsing. */ public function preview() { $this->batch = $this->importer->fetcher->fetch($this); $this->importer->parser->parse($this->batch, $this); module_invoke_all('feeds_after_parse', $this->importer, $this); $batch = $this->batch; unset($this->batch); return $batch; } /** * Import a feed: execute fetching, parsing and processing stage. * * @return * FEEDS_BATCH_COMPLETE if the import process finished. A decimal between * 0.0 and 0.9 periodic if import is still in progress. * * @throws * Throws Exception if an error occurs when importing. */ public function import() { try { if (!$this->batch || !($this->batch instanceof FeedsImportBatch)) { $this->batch = $this->importer->fetcher->fetch($this); $this->importer->parser->parse($this->batch, $this); module_invoke_all('feeds_after_parse', $this->importer, $this); } $this->importer->processor->process($this->batch, $this); $result = $this->batch->getProgress(); if ($result == FEEDS_BATCH_COMPLETE) { unset($this->batch); module_invoke_all('feeds_after_import', $this->importer, $this); } } catch (Exception $e) { unset($this->batch); $this->save(); throw $e; } $this->save(); return $result; } /** * Remove all items from a feed. * * @return * FEEDS_BATCH_COMPLETE if the clearing process finished. A decimal between * 0.0 and 0.9 periodic if clearing is still in progress. * * @throws * Throws Exception if an error occurs when clearing. */ public function clear() { try { $this->importer->fetcher->clear($this); $this->importer->parser->clear($this); if (!$this->batch || !($this->batch instanceof FeedsClearBatch)) { $this->batch = new FeedsClearBatch(); } $this->importer->processor->clear($this->batch, $this); $result = $this->batch->getProgress(); if ($result == FEEDS_BATCH_COMPLETE) { unset($this->batch); module_invoke_all('feeds_after_clear', $this->importer, $this); } } catch (Exception $e) { unset($this->batch); $this->save(); throw $e; } $this->save(); return $result; } /** * Schedule this source. */ public function schedule() { // Check whether any fetcher is overriding the import period. $period = $this->importer->config['import_period']; $fetcher_period = $this->importer->fetcher->importPeriod($this); if (is_numeric($fetcher_period)) { $period = $fetcher_period; } $job = array( 'callback' => 'feeds_source_import', 'type' => $this->id, 'id' => $this->feed_nid, // Schedule as soon as possible if a batch is active. 'period' => $this->batch ? 0 : $period, 'periodic' => TRUE, ); if ($job['period'] != FEEDS_SCHEDULE_NEVER) { job_scheduler()->set($job); } else { job_scheduler()->remove($job); } } /** * Save configuration. */ public function save() { $config = $this->getConfig(); // Alert implementers of FeedsSourceInterface to the fact that we're saving. foreach ($this->importer->plugin_types as $type) { $this->importer->$type->sourceSave($this); } // Store the source property of the fetcher in a separate column so that we // can do fast lookups on it. $source = ''; if (isset($config[get_class($this->importer->fetcher)]['source'])) { $source = $config[get_class($this->importer->fetcher)]['source']; } $object = array( 'id' => $this->id, 'feed_nid' => $this->feed_nid, 'config' => $config, 'source' => $source, 'batch' => isset($this->batch) ? $this->batch : FALSE, ); if (db_result(db_query_range("SELECT 1 FROM {feeds_source} WHERE id = '%s' AND feed_nid = %d", $this->id, $this->feed_nid, 0, 1))) { drupal_write_record('feeds_source', $object, array('id', 'feed_nid')); } else { drupal_write_record('feeds_source', $object); } } /** * Load configuration and unpack. * * @todo Patch CTools to move constants from export.inc to ctools.module. */ public function load() { if ($record = db_fetch_object(db_query("SELECT config, batch FROM {feeds_source} WHERE id = '%s' AND feed_nid = %d", $this->id, $this->feed_nid))) { // While FeedsSource cannot be exported, we still use CTool's export.inc // export definitions. ctools_include('export'); $this->export_type = EXPORT_IN_DATABASE; $this->config = unserialize($record->config); $this->batch = unserialize($record->batch); } } /** * Delete configuration. Removes configuration information * from database, does not delete configuration itself. */ public function delete() { // Alert implementers of FeedsSourceInterface to the fact that we're // deleting. foreach ($this->importer->plugin_types as $type) { $this->importer->$type->sourceDelete($this); } db_query("DELETE FROM {feeds_source} WHERE id = '%s' AND feed_nid = %d", $this->id, $this->feed_nid); // Remove from schedule. $job = array( 'callback' => 'feeds_source_import', 'type' => $this->id, 'id' => $this->feed_nid, ); job_scheduler()->remove($job); } /** * Only return source if configuration is persistent and valid. * * @see FeedsConfigurable::existing(). */ public function existing() { // If there is no feed nid given, there must be no content type specified. // If there is a feed nid given, there must be a content type specified. // Ensure that importer is persistent (= defined in code or DB). // Ensure that source is persistent (= defined in DB). if ((empty($this->feed_nid) && empty($this->importer->config['content_type'])) || (!empty($this->feed_nid) && !empty($this->importer->config['content_type']))) { $this->importer->existing(); return parent::existing(); } throw new FeedsNotExistingException(t('Source configuration not valid.')); } /** * Convenience function. Returns the configuration for a specific class. * * @param FeedsSourceInterface $client * An object that is an implementer of FeedsSourceInterface. * * @return * An array stored for $client. */ public function getConfigFor(FeedsSourceInterface $client) { return $this->config[get_class($client)]; } /** * Return defaults for feed configuration. */ public function configDefaults() { // Collect information from plugins. $defaults = array(); foreach ($this->importer->plugin_types as $type) { if ($this->importer->$type->hasSourceConfig()) { $defaults[get_class($this->importer->$type)] = $this->importer->$type->sourceDefaults(); } } return $defaults; } /** * Override parent::configForm(). */ public function configForm(&$form_state) { // Collect information from plugins. $form = array(); foreach ($this->importer->plugin_types as $type) { if ($this->importer->$type->hasSourceConfig()) { $class = get_class($this->importer->$type); $form[$class] = $this->importer->$type->sourceForm($this->config[$class]); $form[$class]['#tree'] = TRUE; } } return $form; } /** * Override parent::configFormValidate(). */ public function configFormValidate(&$values) { foreach ($this->importer->plugin_types as $type) { $class = get_class($this->importer->$type); if (isset($values[$class]) && $this->importer->$type->hasSourceConfig()) { $this->importer->$type->sourceFormValidate($values[$class]); } } } }