FeedsSource.inc

  1. cis7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
  2. cle7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
  3. ecd7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
  4. elmsmedia7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
  5. harmony7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
  6. icor7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
  7. meedjum_blog7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
  8. mooc7 sites/all/modules/ulmus/feeds/includes/FeedsSource.inc

Definition of FeedsSourceInterface and FeedsSource class.

Constants

Namesort descending Description
FEEDS_FETCH
FEEDS_PARSE
FEEDS_PROCESS
FEEDS_PROCESS_CLEAR
FEEDS_START Denote a import or clearing stage. Used for multi page processing.

Classes

Namesort descending Description
FeedsLockException Distinguish exceptions occuring when handling locks.
FeedsSource This class encapsulates a source of a feed. It stores where the feed can be found and how to import it.
FeedsState Status of an import or clearing operation on a source.

Interfaces

Namesort descending Description
FeedsSourceInterface Declares an interface for a class that defines default values and form descriptions for a FeedSource.

File

sites/all/modules/ulmus/feeds/includes/FeedsSource.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Definition of FeedsSourceInterface and FeedsSource class.
  5. */
  6. /**
  7. * Distinguish exceptions occuring when handling locks.
  8. */
  9. class FeedsLockException extends Exception {}
  10. /**
  11. * Denote a import or clearing stage. Used for multi page processing.
  12. */
  13. define('FEEDS_START', 'start_time');
  14. define('FEEDS_FETCH', 'fetch');
  15. define('FEEDS_PARSE', 'parse');
  16. define('FEEDS_PROCESS', 'process');
  17. define('FEEDS_PROCESS_CLEAR', 'process_clear');
  18. /**
  19. * Declares an interface for a class that defines default values and form
  20. * descriptions for a FeedSource.
  21. */
  22. interface FeedsSourceInterface {
  23. /**
  24. * Crutch: for ease of use, we implement FeedsSourceInterface for every
  25. * plugin, but then we need to have a handle which plugin actually implements
  26. * a source.
  27. *
  28. * @see FeedsPlugin class.
  29. *
  30. * @return
  31. * TRUE if a plugin handles source specific configuration, FALSE otherwise.
  32. */
  33. public function hasSourceConfig();
  34. /**
  35. * Return an associative array of default values.
  36. */
  37. public function sourceDefaults();
  38. /**
  39. * Return a Form API form array that defines a form configuring values. Keys
  40. * correspond to the keys of the return value of sourceDefaults().
  41. */
  42. public function sourceForm($source_config);
  43. /**
  44. * Validate user entered values submitted by sourceForm().
  45. */
  46. public function sourceFormValidate(&$source_config);
  47. /**
  48. * A source is being saved.
  49. */
  50. public function sourceSave(FeedsSource $source);
  51. /**
  52. * A source is being deleted.
  53. */
  54. public function sourceDelete(FeedsSource $source);
  55. }
  56. /**
  57. * Status of an import or clearing operation on a source.
  58. */
  59. class FeedsState {
  60. /**
  61. * Floating point number denoting the progress made. 0.0 meaning no progress
  62. * 1.0 = FEEDS_BATCH_COMPLETE meaning finished.
  63. */
  64. public $progress;
  65. /**
  66. * Used as a pointer to store where left off. Must be serializable.
  67. */
  68. public $pointer;
  69. /**
  70. * Natural numbers denoting more details about the progress being made.
  71. */
  72. public $total;
  73. public $created;
  74. public $updated;
  75. public $deleted;
  76. public $skipped;
  77. public $failed;
  78. /**
  79. * Constructor, initialize variables.
  80. */
  81. public function __construct() {
  82. $this->progress = FEEDS_BATCH_COMPLETE;
  83. $this->total =
  84. $this->created =
  85. $this->updated =
  86. $this->deleted =
  87. $this->skipped =
  88. $this->failed = 0;
  89. }
  90. /**
  91. * Safely report progress.
  92. *
  93. * When $total == $progress, the state of the task tracked by this state is
  94. * regarded to be complete.
  95. *
  96. * Handles the following cases gracefully:
  97. *
  98. * - $total is 0
  99. * - $progress is larger than $total
  100. * - $progress approximates $total so that $finished rounds to 1.0
  101. *
  102. * @param $total
  103. * A natural number that is the total to be worked off.
  104. * @param $progress
  105. * A natural number that is the progress made on $total.
  106. */
  107. public function progress($total, $progress) {
  108. if ($progress > $total) {
  109. $this->progress = FEEDS_BATCH_COMPLETE;
  110. }
  111. elseif ($total) {
  112. $this->progress = $progress / $total;
  113. if ($this->progress == FEEDS_BATCH_COMPLETE && $total != $progress) {
  114. $this->progress = 0.99;
  115. }
  116. }
  117. else {
  118. $this->progress = FEEDS_BATCH_COMPLETE;
  119. }
  120. }
  121. }
  122. /**
  123. * This class encapsulates a source of a feed. It stores where the feed can be
  124. * found and how to import it.
  125. *
  126. * Information on how to import a feed is encapsulated in a FeedsImporter object
  127. * which is identified by the common id of the FeedsSource and the
  128. * FeedsImporter. More than one FeedsSource can use the same FeedsImporter
  129. * therefore a FeedsImporter never holds a pointer to a FeedsSource object, nor
  130. * does it hold any other information for a particular FeedsSource object.
  131. *
  132. * Classes extending FeedsPlugin can implement a sourceForm to expose
  133. * configuration for a FeedsSource object. This is for instance how FeedsFetcher
  134. * exposes a text field for a feed URL or how FeedsCSVParser exposes a select
  135. * field for choosing between colon or semicolon delimiters.
  136. *
  137. * It is important that a FeedsPlugin does not directly hold information about
  138. * a source but leave all storage up to FeedsSource. An instance of a
  139. * FeedsPlugin class only exists once per FeedsImporter configuration, while an
  140. * instance of a FeedsSource class exists once per feed_nid to be imported.
  141. *
  142. * As with FeedsImporter, the idea with FeedsSource is that it can be used
  143. * without actually saving the object to the database.
  144. */
  145. class FeedsSource extends FeedsConfigurable {
  146. // Contains the node id of the feed this source info object is attached to.
  147. // Equals 0 if not attached to any node - i. e. if used on a
  148. // standalone import form within Feeds or by other API users.
  149. protected $feed_nid;
  150. // The FeedsImporter object that this source is expected to be used with.
  151. protected $importer;
  152. // A FeedsSourceState object holding the current import/clearing state of this
  153. // source.
  154. protected $state;
  155. // Fetcher result, used to cache fetcher result when batching.
  156. protected $fetcher_result;
  157. // Timestamp when this source was imported the last time.
  158. protected $imported;
  159. /**
  160. * Instantiate a unique object per class/id/feed_nid. Don't use
  161. * directly, use feeds_source() instead.
  162. */
  163. public static function instance($importer_id, $feed_nid) {
  164. $class = variable_get('feeds_source_class', 'FeedsSource');
  165. static $instances = array();
  166. if (!isset($instances[$class][$importer_id][$feed_nid])) {
  167. $instances[$class][$importer_id][$feed_nid] = new $class($importer_id, $feed_nid);
  168. }
  169. return $instances[$class][$importer_id][$feed_nid];
  170. }
  171. /**
  172. * Constructor.
  173. */
  174. protected function __construct($importer_id, $feed_nid) {
  175. $this->feed_nid = $feed_nid;
  176. $this->importer = feeds_importer($importer_id);
  177. parent::__construct($importer_id);
  178. $this->load();
  179. }
  180. /**
  181. * Returns the FeedsImporter object that this source is expected to be used with.
  182. */
  183. public function importer() {
  184. return $this->importer;
  185. }
  186. /**
  187. * Preview = fetch and parse a feed.
  188. *
  189. * @return
  190. * FeedsParserResult object.
  191. *
  192. * @throws
  193. * Throws Exception if an error occurs when fetching or parsing.
  194. */
  195. public function preview() {
  196. $result = $this->importer->fetcher->fetch($this);
  197. $result = $this->importer->parser->parse($this, $result);
  198. module_invoke_all('feeds_after_parse', $this, $result);
  199. return $result;
  200. }
  201. /**
  202. * Start importing a source.
  203. *
  204. * This method starts an import job. Depending on the configuration of the
  205. * importer of this source, a Batch API job or a background job with Job
  206. * Scheduler will be created.
  207. *
  208. * @throws Exception
  209. * If processing in background is enabled, the first batch chunk of the
  210. * import will be executed on the current page request. This means that this
  211. * method may throw the same exceptions as FeedsSource::import().
  212. */
  213. public function startImport() {
  214. $config = $this->importer->getConfig();
  215. if ($config['process_in_background']) {
  216. $this->startBackgroundJob('import');
  217. }
  218. else {
  219. $this->startBatchAPIJob(t('Importing'), 'import');
  220. }
  221. }
  222. /**
  223. * Start deleting all imported items of a source.
  224. *
  225. * This method starts a clear job. Depending on the configuration of the
  226. * importer of this source, a Batch API job or a background job with Job
  227. * Scheduler will be created.
  228. *
  229. * @throws Exception
  230. * If processing in background is enabled, the first batch chunk of the
  231. * clear task will be executed on the current page request. This means that
  232. * this method may throw the same exceptions as FeedsSource::clear().
  233. */
  234. public function startClear() {
  235. $config = $this->importer->getConfig();
  236. if ($config['process_in_background']) {
  237. $this->startBackgroundJob('clear');
  238. }
  239. else {
  240. $this->startBatchAPIJob(t('Deleting'), 'clear');
  241. }
  242. }
  243. /**
  244. * Schedule all periodic tasks for this source.
  245. */
  246. public function schedule() {
  247. $this->scheduleImport();
  248. }
  249. /**
  250. * Schedule periodic or background import tasks.
  251. */
  252. public function scheduleImport() {
  253. // Check whether any fetcher is overriding the import period.
  254. $period = $this->importer->config['import_period'];
  255. $fetcher_period = $this->importer->fetcher->importPeriod($this);
  256. if (is_numeric($fetcher_period)) {
  257. $period = $fetcher_period;
  258. }
  259. $period = $this->progressImporting() === FEEDS_BATCH_COMPLETE ? $period : 0;
  260. $job = array(
  261. 'type' => $this->id,
  262. 'id' => $this->feed_nid,
  263. // Schedule as soon as possible if a batch is active.
  264. 'period' => $period,
  265. 'periodic' => TRUE,
  266. );
  267. if ($period != FEEDS_SCHEDULE_NEVER) {
  268. JobScheduler::get('feeds_source_import')->set($job);
  269. }
  270. else {
  271. JobScheduler::get('feeds_source_import')->remove($job);
  272. }
  273. }
  274. /**
  275. * Schedule background clearing tasks.
  276. */
  277. public function scheduleClear() {
  278. $job = array(
  279. 'type' => $this->id,
  280. 'id' => $this->feed_nid,
  281. 'period' => 0,
  282. 'periodic' => TRUE,
  283. );
  284. // Remove job if batch is complete.
  285. if ($this->progressClearing() === FEEDS_BATCH_COMPLETE) {
  286. JobScheduler::get('feeds_source_clear')->remove($job);
  287. }
  288. // Schedule as soon as possible if batch is not complete.
  289. else {
  290. JobScheduler::get('feeds_source_clear')->set($job);
  291. }
  292. }
  293. /**
  294. * Import a source: execute fetching, parsing and processing stage.
  295. *
  296. * This method only executes the current batch chunk, then returns. If you are
  297. * looking to import an entire source, use FeedsSource::startImport() instead.
  298. *
  299. * @return
  300. * FEEDS_BATCH_COMPLETE if the import process finished. A decimal between
  301. * 0.0 and 0.9 periodic if import is still in progress.
  302. *
  303. * @throws
  304. * Throws Exception if an error occurs when importing.
  305. */
  306. public function import() {
  307. $this->acquireLock();
  308. try {
  309. // If fetcher result is empty, we are starting a new import, log.
  310. if (empty($this->fetcher_result)) {
  311. $this->state[FEEDS_START] = time();
  312. }
  313. // Fetch.
  314. if (empty($this->fetcher_result) || FEEDS_BATCH_COMPLETE == $this->progressParsing()) {
  315. $this->fetcher_result = $this->importer->fetcher->fetch($this);
  316. // Clean the parser's state, we are parsing an entirely new file.
  317. unset($this->state[FEEDS_PARSE]);
  318. }
  319. // Parse.
  320. $parser_result = $this->importer->parser->parse($this, $this->fetcher_result);
  321. module_invoke_all('feeds_after_parse', $this, $parser_result);
  322. // Process.
  323. $this->importer->processor->process($this, $parser_result);
  324. }
  325. catch (Exception $e) {
  326. // Do nothing.
  327. }
  328. $this->releaseLock();
  329. // Clean up.
  330. $result = $this->progressImporting();
  331. if ($result == FEEDS_BATCH_COMPLETE || isset($e)) {
  332. $this->imported = time();
  333. $this->log('import', 'Imported in !s s', array('!s' => $this->imported - $this->state[FEEDS_START]), WATCHDOG_INFO);
  334. module_invoke_all('feeds_after_import', $this);
  335. unset($this->fetcher_result, $this->state);
  336. }
  337. $this->save();
  338. if (isset($e)) {
  339. throw $e;
  340. }
  341. return $result;
  342. }
  343. /**
  344. * Remove all items from a feed.
  345. *
  346. * This method only executes the current batch chunk, then returns. If you are
  347. * looking to delete all items of a source, use FeedsSource::startClear()
  348. * instead.
  349. *
  350. * @return
  351. * FEEDS_BATCH_COMPLETE if the clearing process finished. A decimal between
  352. * 0.0 and 0.9 periodic if clearing is still in progress.
  353. *
  354. * @throws
  355. * Throws Exception if an error occurs when clearing.
  356. */
  357. public function clear() {
  358. $this->acquireLock();
  359. try {
  360. $this->importer->fetcher->clear($this);
  361. $this->importer->parser->clear($this);
  362. $this->importer->processor->clear($this);
  363. }
  364. catch (Exception $e) {
  365. // Do nothing.
  366. }
  367. $this->releaseLock();
  368. // Clean up.
  369. $result = $this->progressClearing();
  370. if ($result == FEEDS_BATCH_COMPLETE || isset($e)) {
  371. module_invoke_all('feeds_after_clear', $this);
  372. unset($this->state);
  373. }
  374. $this->save();
  375. if (isset($e)) {
  376. throw $e;
  377. }
  378. return $result;
  379. }
  380. /**
  381. * Report progress as float between 0 and 1. 1 = FEEDS_BATCH_COMPLETE.
  382. */
  383. public function progressParsing() {
  384. return $this->state(FEEDS_PARSE)->progress;
  385. }
  386. /**
  387. * Report progress as float between 0 and 1. 1 = FEEDS_BATCH_COMPLETE.
  388. */
  389. public function progressImporting() {
  390. $fetcher = $this->state(FEEDS_FETCH);
  391. $parser = $this->state(FEEDS_PARSE);
  392. if ($fetcher->progress == FEEDS_BATCH_COMPLETE && $parser->progress == FEEDS_BATCH_COMPLETE) {
  393. return FEEDS_BATCH_COMPLETE;
  394. }
  395. // Fetching envelops parsing.
  396. // @todo: this assumes all fetchers neatly use total. May not be the case.
  397. $fetcher_fraction = $fetcher->total ? 1.0 / $fetcher->total : 1.0;
  398. $parser_progress = $parser->progress * $fetcher_fraction;
  399. $result = $fetcher->progress - $fetcher_fraction + $parser_progress;
  400. if ($result == FEEDS_BATCH_COMPLETE) {
  401. return 0.99;
  402. }
  403. return $result;
  404. }
  405. /**
  406. * Report progress on clearing.
  407. */
  408. public function progressClearing() {
  409. return $this->state(FEEDS_PROCESS_CLEAR)->progress;
  410. }
  411. /**
  412. * Return a state object for a given stage. Lazy instantiates new states.
  413. *
  414. * @todo Rename getConfigFor() accordingly to config().
  415. *
  416. * @param $stage
  417. * One of FEEDS_FETCH, FEEDS_PARSE, FEEDS_PROCESS or FEEDS_PROCESS_CLEAR.
  418. *
  419. * @return
  420. * The FeedsState object for the given stage.
  421. */
  422. public function state($stage) {
  423. if (!is_array($this->state)) {
  424. $this->state = array();
  425. }
  426. if (!isset($this->state[$stage])) {
  427. $this->state[$stage] = new FeedsState();
  428. }
  429. return $this->state[$stage];
  430. }
  431. /**
  432. * Count items imported by this source.
  433. */
  434. public function itemCount() {
  435. return $this->importer->processor->itemCount($this);
  436. }
  437. /**
  438. * Save configuration.
  439. */
  440. public function save() {
  441. // Alert implementers of FeedsSourceInterface to the fact that we're saving.
  442. foreach ($this->importer->plugin_types as $type) {
  443. $this->importer->$type->sourceSave($this);
  444. }
  445. $config = $this->getConfig();
  446. // Store the source property of the fetcher in a separate column so that we
  447. // can do fast lookups on it.
  448. $source = '';
  449. if (isset($config[get_class($this->importer->fetcher)]['source'])) {
  450. $source = $config[get_class($this->importer->fetcher)]['source'];
  451. }
  452. $object = array(
  453. 'id' => $this->id,
  454. 'feed_nid' => $this->feed_nid,
  455. 'imported' => $this->imported,
  456. 'config' => $config,
  457. 'source' => $source,
  458. 'state' => isset($this->state) ? $this->state : FALSE,
  459. 'fetcher_result' => isset($this->fetcher_result) ? $this->fetcher_result : FALSE,
  460. );
  461. if (db_query_range("SELECT 1 FROM {feeds_source} WHERE id = :id AND feed_nid = :nid", 0, 1, array(':id' => $this->id, ':nid' => $this->feed_nid))->fetchField()) {
  462. drupal_write_record('feeds_source', $object, array('id', 'feed_nid'));
  463. }
  464. else {
  465. drupal_write_record('feeds_source', $object);
  466. }
  467. }
  468. /**
  469. * Load configuration and unpack.
  470. *
  471. * @todo Patch CTools to move constants from export.inc to ctools.module.
  472. */
  473. public function load() {
  474. if ($record = db_query("SELECT imported, config, state, fetcher_result FROM {feeds_source} WHERE id = :id AND feed_nid = :nid", array(':id' => $this->id, ':nid' => $this->feed_nid))->fetchObject()) {
  475. // While FeedsSource cannot be exported, we still use CTool's export.inc
  476. // export definitions.
  477. ctools_include('export');
  478. $this->export_type = EXPORT_IN_DATABASE;
  479. $this->imported = $record->imported;
  480. $this->config = unserialize($record->config);
  481. if (!empty($record->state)) {
  482. $this->state = unserialize($record->state);
  483. }
  484. if (!empty($record->fetcher_result)) {
  485. $this->fetcher_result = unserialize($record->fetcher_result);
  486. }
  487. }
  488. }
  489. /**
  490. * Delete configuration. Removes configuration information
  491. * from database, does not delete configuration itself.
  492. */
  493. public function delete() {
  494. // Alert implementers of FeedsSourceInterface to the fact that we're
  495. // deleting.
  496. foreach ($this->importer->plugin_types as $type) {
  497. $this->importer->$type->sourceDelete($this);
  498. }
  499. db_delete('feeds_source')
  500. ->condition('id', $this->id)
  501. ->condition('feed_nid', $this->feed_nid)
  502. ->execute();
  503. // Remove from schedule.
  504. $job = array(
  505. 'type' => $this->id,
  506. 'id' => $this->feed_nid,
  507. );
  508. JobScheduler::get('feeds_source_import')->remove($job);
  509. }
  510. /**
  511. * Only return source if configuration is persistent and valid.
  512. *
  513. * @see FeedsConfigurable::existing().
  514. */
  515. public function existing() {
  516. // If there is no feed nid given, there must be no content type specified.
  517. // If there is a feed nid given, there must be a content type specified.
  518. // Ensure that importer is persistent (= defined in code or DB).
  519. // Ensure that source is persistent (= defined in DB).
  520. if ((empty($this->feed_nid) && empty($this->importer->config['content_type'])) ||
  521. (!empty($this->feed_nid) && !empty($this->importer->config['content_type']))) {
  522. $this->importer->existing();
  523. return parent::existing();
  524. }
  525. throw new FeedsNotExistingException(t('Source configuration not valid.'));
  526. }
  527. /**
  528. * Returns the configuration for a specific client class.
  529. *
  530. * @param FeedsSourceInterface $client
  531. * An object that is an implementer of FeedsSourceInterface.
  532. *
  533. * @return
  534. * An array stored for $client.
  535. */
  536. public function getConfigFor(FeedsSourceInterface $client) {
  537. $class = get_class($client);
  538. return isset($this->config[$class]) ? $this->config[$class] : $client->sourceDefaults();
  539. }
  540. /**
  541. * Sets the configuration for a specific client class.
  542. *
  543. * @param FeedsSourceInterface $client
  544. * An object that is an implementer of FeedsSourceInterface.
  545. * @param $config
  546. * The configuration for $client.
  547. *
  548. * @return
  549. * An array stored for $client.
  550. */
  551. public function setConfigFor(FeedsSourceInterface $client, $config) {
  552. $this->config[get_class($client)] = $config;
  553. }
  554. /**
  555. * Return defaults for feed configuration.
  556. */
  557. public function configDefaults() {
  558. // Collect information from plugins.
  559. $defaults = array();
  560. foreach ($this->importer->plugin_types as $type) {
  561. if ($this->importer->$type->hasSourceConfig()) {
  562. $defaults[get_class($this->importer->$type)] = $this->importer->$type->sourceDefaults();
  563. }
  564. }
  565. return $defaults;
  566. }
  567. /**
  568. * Override parent::configForm().
  569. */
  570. public function configForm(&$form_state) {
  571. // Collect information from plugins.
  572. $form = array();
  573. foreach ($this->importer->plugin_types as $type) {
  574. if ($this->importer->$type->hasSourceConfig()) {
  575. $class = get_class($this->importer->$type);
  576. $config = isset($this->config[$class]) ? $this->config[$class] : array();
  577. $form[$class] = $this->importer->$type->sourceForm($config);
  578. $form[$class]['#tree'] = TRUE;
  579. }
  580. }
  581. return $form;
  582. }
  583. /**
  584. * Override parent::configFormValidate().
  585. */
  586. public function configFormValidate(&$values) {
  587. foreach ($this->importer->plugin_types as $type) {
  588. $class = get_class($this->importer->$type);
  589. if (isset($values[$class]) && $this->importer->$type->hasSourceConfig()) {
  590. $this->importer->$type->sourceFormValidate($values[$class]);
  591. }
  592. }
  593. }
  594. /**
  595. * Writes to feeds log.
  596. */
  597. public function log($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE) {
  598. feeds_log($this->id, $this->feed_nid, $type, $message, $variables, $severity);
  599. }
  600. /**
  601. * Background job helper. Starts a background job using Job Scheduler.
  602. *
  603. * Execute the first batch chunk of a background job on the current page load,
  604. * moves the rest of the job processing to a cron powered background job.
  605. *
  606. * Executing the first batch chunk is important, otherwise, when a user
  607. * submits a source for import or clearing, we will leave her without any
  608. * visual indicators of an ongoing job.
  609. *
  610. * @see FeedsSource::startImport().
  611. * @see FeedsSource::startClear().
  612. *
  613. * @param $method
  614. * Method to execute on importer; one of 'import' or 'clear'.
  615. *
  616. * @throws Exception $e
  617. */
  618. protected function startBackgroundJob($method) {
  619. if (FEEDS_BATCH_COMPLETE != $this->$method()) {
  620. $job = array(
  621. 'type' => $this->id,
  622. 'id' => $this->feed_nid,
  623. 'period' => 0,
  624. 'periodic' => FALSE,
  625. );
  626. JobScheduler::get("feeds_source_{$method}")->set($job);
  627. }
  628. }
  629. /**
  630. * Batch API helper. Starts a Batch API job.
  631. *
  632. * @see FeedsSource::startImport().
  633. * @see FeedsSource::startClear().
  634. * @see feeds_batch()
  635. *
  636. * @param $title
  637. * Title to show to user when executing batch.
  638. * @param $method
  639. * Method to execute on importer; one of 'import' or 'clear'.
  640. */
  641. protected function startBatchAPIJob($title, $method) {
  642. $batch = array(
  643. 'title' => $title,
  644. 'operations' => array(
  645. array('feeds_batch', array($method, $this->id, $this->feed_nid)),
  646. ),
  647. 'progress_message' => '',
  648. );
  649. batch_set($batch);
  650. }
  651. /**
  652. * Acquires a lock for this source.
  653. *
  654. * @throws FeedsLockException
  655. * If a lock for the requested job could not be acquired.
  656. */
  657. protected function acquireLock() {
  658. if (!lock_acquire("feeds_source_{$this->id}_{$this->feed_nid}", 60.0)) {
  659. throw new FeedsLockException(t('Cannot acquire lock for source @id / @feed_nid.', array('@id' => $this->id, '@feed_nid' => $this->feed_nid)));
  660. }
  661. }
  662. /**
  663. * Releases a lock for this source.
  664. */
  665. protected function releaseLock() {
  666. lock_release("feeds_source_{$this->id}_{$this->feed_nid}");
  667. }
  668. }
Error | ELMSLN API

Error

×

Error message

  • Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/elmsln_community/api.elmsln.org/includes/common.inc:2791) in drupal_send_headers() (line 1499 of /var/www/html/elmsln_community/api.elmsln.org/includes/bootstrap.inc).
  • Error: Call to undefined function apc_delete() in DrupalAPCCache->clear() (line 289 of /var/www/html/elmsln_community/api.elmsln.org/sites/all/modules/apc/drupal_apc_cache.inc).
The website encountered an unexpected error. Please try again later.