/** * Lists the feed items belonging to a feed. */ public function listItems(FeedInterface $feeds_feed, Request $request) { $processor = $feeds_feed->getType()->getProcessor(); $header = ['title' => $this->t('Label'), 'imported' => $this->t('Imported'), 'guid' => ['data' => $this->t('GUID'), 'class' => [RESPONSIVE_PRIORITY_LOW]], 'url' => ['data' => $this->t('URL'), 'class' => [RESPONSIVE_PRIORITY_LOW]]]; $build = []; $build['table'] = ['#type' => 'table', '#header' => $header, '#rows' => [], '#empty' => $this->t('There are no items yet.')]; // @todo Allow processors to create their own entity listings. if (!$processor instanceof EntityProcessorInterface) { return $build; } $entity_ids = \Drupal::entityQuery($processor->entityType())->condition('feeds_item.target_id', $feeds_feed->id())->pager(50)->sort('feeds_item.imported', 'DESC')->execute(); $storage = $this->entityManager()->getStorage($processor->entityType()); foreach ($storage->loadMultiple($entity_ids) as $entity) { $ago = \Drupal::service('date.formatter')->formatInterval(REQUEST_TIME - $entity->get('feeds_item')->imported); $row = []; // Entity link. $row[] = ['data' => $entity->link(Unicode::truncate($entity->label(), 75, TRUE, TRUE)), 'title' => $entity->label()]; // Imported ago. $row[] = $this->t('@time ago', ['@time' => $ago]); // Item GUID. $row[] = ['data' => SafeMarkup::checkPlain(Unicode::truncate($entity->get('feeds_item')->guid, 30, FALSE, TRUE)), 'title' => $entity->get('feeds_item')->guid]; // Item URL. $row[] = ['data' => SafeMarkup::checkPlain(Unicode::truncate($entity->get('feeds_item')->url, 30, FALSE, TRUE)), 'title' => $entity->get('feeds_item')->url]; $build['table']['#rows'][] = $row; } $build['pager'] = ['#type' => 'pager']; $build['#title'] = $this->t('%title items', ['%title' => $feeds_feed->label()]); return $build; }
/** * {@inheritdoc} */ public function parse(FeedInterface $feed, FetcherResultInterface $fetcher_result) { $feed_config = $feed->getConfigurationFor($this); $state = $feed->getState(StateInterface::PARSE); // Load and configure parser. $parser = new ParserCSV(); $delimiter = $feed_config['delimiter'] == 'TAB' ? "\t" : $feed_config['delimiter']; $parser->setDelimiter($delimiter); $iterator = new ParserCSVIterator($fetcher_result->getFilePath()); if (empty($feed_config['no_headers'])) { // Get first line and use it for column names, convert them to lower case. $header = $this->parseHeader($parser, $iterator); if (!$header) { return; } $parser->setColumnNames($header); } // Determine section to parse, parse. $start = $state->pointer ? $state->pointer : $parser->lastLinePos(); $limit = $this->importer->getLimit(); $rows = $this->parseItems($parser, $iterator, $start, $limit); // Report progress. $state->total = filesize($fetcher_result->getFilePath()); $state->pointer = $parser->lastLinePos(); $progress = $parser->lastLinePos() ? $parser->lastLinePos() : $state->total; $state->progress($state->total, $progress); // Create a result object and return it. return new ParserResult($rows, $feed->id()); }
/** * Executes a callback. * * @param \Drupal\feeds\FeedInterface $feeds_feed * The Feed we are executing a job for. * @param \Symfony\Component\HttpFoundation\Request $request * The request object to grab POST params from. * * @todo Configure a time limit. * @todo Really awesome error handling. */ public function execute(FeedInterface $feeds_feed, Request $request) { $cid = 'feeds_feed:' . $feeds_feed->id(); if ($token = $request->request->get('token') && ($job = $this->state->get($cid))) { if ($job['token'] == $token && ($lock = $this->lockBackend->acquire($cid))) { $method = $job['method']; $this->state->delete($cid); ignore_user_abort(TRUE); set_time_limit(0); while ($feeds_feed->{$method}() != StateInterface::BATCH_COMPLETE) { // Reset static caches in between runs to avoid memory leaks. drupal_reset_static(); } $this->lockBackend->release($cid); } } }
/** * Returns the download cache key for a given feed. * * @param \Drupal\feeds\FeedInterface $feed * The feed to find the cache key for. * * @return string * The cache key for the feed. */ protected function getCacheKey(FeedInterface $feed) { return $feed->id() . ':' . md5($feed->getSource()); }
/** * Schedule background expire tasks. * * This is also used as a callback for job_scheduler integration. * * @param \Drupal\feeds\FeedInterface $feed * The feed to schedule. */ public function scheduleExpire(FeedInterface $feed) { if (!$this->jobController) { return; } // Schedule as soon as possible if a batch is active. $period = $feed->progressExpiring() === StateInterface::BATCH_COMPLETE ? 3600 : 0; $job = array('name' => 'feeds_feed_expire', 'type' => $feed->bundle(), 'id' => $feed->id(), 'period' => $period, 'periodic' => TRUE); if ($feed->getImporter()->getProcessor()->expiryTime() == SchedulerInterface::EXPIRE_NEVER) { $this->jobController->remove($job); } else { $this->jobController->set($job); } }
/** * {@inheritdoc} */ public function onFeedSave(FeedInterface $feed, $update) { // We are only interested in continuing if we came from a form submit. if (!$this->feedConfig) { return; } // New file found. if ($this->feedConfig['new_fid'] != $this->feedConfig['fid']) { $this->deleteFile($this->feedConfig['fid'], $feed->id()); if ($this->feedConfig['new_fid']) { $file = $this->fileStorage->load($this->feedConfig['new_fid']); $this->fileUsage->add($file, 'feeds', $this->pluginType(), $feed->id()); $file->setPermanent(); $file->save(); $this->feedConfig['fid'] = $this->feedConfig['new_fid']; $this->feedConfig['source'] = $file->getFileUri(); $feed->setConfigurationFor($this, $this->feedConfig); } } }
protected function getUniqueQuery(FeedInterface $feed) { if (!isset(static::$uniqueQueries[$feed->id()])) { $entity_type = $feed->getImporter()->getProcessor()->entityType(); static::$uniqueQueries[$feed->id()] = \Drupal::entityQuery($entity_type)->condition('feeds_item.target_id', $feed->id())->range(0, 1); } return clone static::$uniqueQueries[$feed->id()]; }
/** * Starts a Batch API job. * * @param \Drupal\feeds\FeedInterface $feed * The feed to start the job for. * @param string $title * Title to show to user when executing batch. * @param string $method * Method to execute on importer; one of 'import' or 'clear'. */ protected function startBatchAPIJob(FeedInterface $feed, $title, $method) { $batch = array('title' => $title, 'operations' => array(array('feeds_batch', array($method, $feed->id()))), 'progress_message' => ''); batch_set($batch); }
/** * {@inheritdoc} */ public function getItemCount(FeedInterface $feed) { return $this->queryFactory->get($this->entityType())->condition('feeds_item.target_id', $feed->id())->count()->execute(); }
/** * {@inheritdoc} */ public function importPeriod(FeedInterface $feed) { $sub = $this->subscription->getSubscription($feed->id()); if ($sub && $sub['state'] == 'subscribed') { // Delay for three days if there is a successful subscription. return 259200; } }
/** * Receives a notification. * * @param \Drupal\feeds\FeedInterface $feeds_feed * The feed to perform the request on. * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * * @return Symfony\Component\HttpFoundation\Response * The response object. * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * Thrown if the subscription was not found or the request parameters were * invalid. */ public function receive(FeedInterface $feeds_feed, Request $request) { if (!($sig = $request->headers->get('X-Hub-Signature'))) { throw new NotFoundHttpException(); } $result = array(); parse_str($sig, $result); if (empty($result['sha1'])) { throw new NotFoundHttpException(); } if (!($sub = $this->subscriptionCrud->getSubscription($feeds_feed->id()))) { throw new NotFoundHttpException(); } $raw = file_get_contents('php://input'); if ($result['sha1'] !== hash_hmac('sha1', $raw, $sub['secret'])) { throw new NotFoundHttpException(); } try { $feeds_feed->importRaw($raw); } catch (InterfaceNotImplementedException $e) { // The fetcher does not support PuSH updates. throw new NotFoundHttpException(); } return new Response('', 200); }