Пример #1
0
 /**
  * Handles an import exception.
  */
 protected function handleException(FeedInterface $feed, \Exception $exception)
 {
     $feed->finishImport();
     if (!$exception instanceof EmptyFeedException) {
         throw $exception;
     }
 }
Пример #2
0
 /**
  * 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;
 }
Пример #3
0
 /**
  * {@inheritdoc}
  */
 public function buildFeedForm(array $form, FormStateInterface $form_state, FeedInterface $feed)
 {
     $feed_config = $feed->getConfigurationFor($this);
     $form['parser']['#tree'] = TRUE;
     $form['parser']['#weight'] = -10;
     $form['parser']['delimiter'] = ['#type' => 'select', '#title' => $this->t('Delimiter'), '#description' => $this->t('The character that delimits fields in the CSV file.'), '#options' => [',' => ',', ';' => ';', 'TAB' => 'TAB', '|' => '|', '+' => '+'], '#default_value' => $feed_config['delimiter']];
     $form['parser']['no_headers'] = ['#type' => 'checkbox', '#title' => $this->t('No Headers'), '#description' => $this->t("Check if the imported CSV file does not start with a header row. If checked, mapping sources must be named '0', '1', '2' etc."), '#default_value' => $feed_config['no_headers']];
     return $form;
 }
Пример #4
0
 /**
  * {@inheritdoc}
  */
 public function postClear(FeedInterface $feed, StateInterface $state)
 {
     $tokens = ['@item' => $this->getItemLabel(), '@items' => $this->getItemLabelPlural(), '%title' => $feed->label()];
     if ($state->deleted) {
         $state->setMessage($this->formatPlural($state->deleted, 'Deleted @count @item from %title.', 'Deleted @count @items from %title.', $tokens));
     } else {
         $state->setMessage($this->t('There are no @items to delete.', $tokens));
     }
 }
Пример #5
0
 /**
  * Finalizes the import.
  */
 protected function finish(FeedInterface $feed, FetcherResultInterface $fetcher_result)
 {
     if ($feed->progressParsing() !== StateInterface::BATCH_COMPLETE) {
         $this->queueFactory->get('feeds_feed_import:' . $feed->bundle())->createItem($feed);
     } elseif ($feed->progressFetching() !== StateInterface::BATCH_COMPLETE) {
         $this->queueFactory->get('feeds_feed_parse:' . $feed->bundle())->createItem($feed, $fetcher_result);
     } else {
         $feed->finishImport();
     }
 }
Пример #6
0
 public function postExpire(FeedInterface $feed)
 {
     $state = $feed->getState(StateInterface::EXPIRE);
     if ($state->total) {
         drupal_set_message(t('Expired @count items.', ['@count' => $state->total]));
     }
     $feed->clearStates();
     $feed->save();
     $feed->unlock();
 }
Пример #7
0
 /**
  * {@inheritdoc}
  *
  * @todo I guess we could cache this since the value will be the same for
  *   $element_key/$feed id combo.
  */
 public function getSourceElement(FeedInterface $feed, array $item, $element_key)
 {
     list(, $field) = explode(':', $element_key);
     $return = array();
     if ($field_list = $feed->get($field)) {
         foreach ($field_list as $field) {
             $return[] = $field->value;
         }
     }
     return $return;
 }
Пример #8
0
 /**
  * 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);
         }
     }
 }
Пример #9
0
 /**
  * {@inheritdoc}
  */
 public function parse(FeedInterface $feed, FetcherResultInterface $fetcher_result, StateInterface $state)
 {
     $result = new ParserResult();
     Reader::setExtensionManager(\Drupal::service('feed.bridge.reader'));
     Reader::registerExtension('GeoRSS');
     $raw = $fetcher_result->getRaw();
     if (!strlen(trim($raw))) {
         throw new EmptyFeedException();
     }
     try {
         $channel = Reader::importString($raw);
     } catch (ExceptionInterface $e) {
         $args = ['%site' => $feed->label(), '%error' => trim($e->getMessage())];
         throw new \RuntimeException($this->t('The feed from %site seems to be broken because of error "%error".', $args));
     }
     foreach ($channel as $delta => $entry) {
         $item = new SyndicationItem();
         // Move the values to an array as expected by processors.
         $item->set('title', $entry->getTitle())->set('guid', $entry->getId())->set('url', $entry->getLink())->set('guid', $entry->getId())->set('url', $entry->getLink())->set('description', $entry->getDescription())->set('tags', $entry->getCategories()->getValues())->set('feed_title', $channel->getTitle())->set('feed_description', $channel->getDescription())->set('feed_url', $channel->getLink());
         if ($image = $channel->getImage()) {
             $item->set('feed_image_uri', $image['uri']);
         }
         if ($enclosure = $entry->getEnclosure()) {
             $item->set('enclosures', [rawurldecode($enclosure->url)]);
         }
         if ($author = $entry->getAuthor()) {
             $author += ['name' => '', 'email' => ''];
             $item->set('author_name', $author['name'])->set('author_email', $author['email']);
         }
         if ($date = $entry->getDateModified()) {
             $item->set('timestamp', $date->getTimestamp());
         }
         if ($point = $entry->getGeoPoint()) {
             $item->set('georss_lat', $point['lat'])->set('georss_lon', $point['lon']);
         }
         $result->addItem($item);
     }
     return $result;
 }
Пример #10
0
 /**
  * {@inheritdoc}
  */
 public function parse(FeedInterface $feed, FetcherResultInterface $fetcher_result, StateInterface $state)
 {
     // Set time zone to GMT for parsing dates with strtotime().
     $tz = date_default_timezone_get();
     date_default_timezone_set('GMT');
     // Reset item counter.
     $this->items_count = 0;
     // Get raw data.
     $raw = trim($fetcher_result->getRaw());
     if (!strlen($raw)) {
         throw new EmptyFeedException();
     }
     $data = Json::decode($raw);
     $result = new ParserResult();
     if ($data && count($data['items']) > 0) {
         $this->processItems($data['items'], $result);
     }
     if ($data['pageInfo']['totalResults'] && $data['pageInfo']['resultsPerPage'] && $data['pageInfo']['totalResults'] > $data['pageInfo']['resultsPerPage']) {
         $number_of_pages = $data['pageInfo']['totalResults'] / $data['pageInfo']['resultsPerPage'];
         if ($number_of_pages > 1) {
             $feed_type = $feed->getType();
             $fetcher_configuration = $feed_type->getFetcher()->getConfiguration();
             $yt_state = ['channel_id' => $feed->getSource(), 'api_key' => $fetcher_configuration['api_key'], 'import_limit' => $fetcher_configuration['import_limit'], 'page_limit' => $fetcher_configuration['page_limit'], 'pageToken' => ''];
             for ($i = 0; $i <= $number_of_pages; $i++) {
                 if (!$data) {
                     throw new EmptyFeedException();
                 }
                 if ($data['nextPageToken']) {
                     $yt_state['pageToken'] = $data['nextPageToken'];
                     $data = Json::decode($this->fetchInternal($feed, $yt_state));
                     $this->processItems($data['items'], $result);
                 }
             }
         }
     }
     date_default_timezone_set($tz);
     return $result;
 }
Пример #11
0
 /**
  * {@inheritdoc}
  */
 public function parse(FeedInterface $feed, FetcherResultInterface $fetcher_result)
 {
     $result = new ParserResult();
     Reader::setExtensionManager(\Drupal::service('feed.bridge.reader'));
     try {
         $channel = Reader::importString($fetcher_result->getRaw());
     } catch (ExceptionInterface $e) {
         watchdog_exception('feeds', $e);
         drupal_set_message($this->t('The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $e->getMessage())), 'error');
         return $result;
     }
     $result->title = $channel->getTitle();
     $result->description = $channel->getDescription();
     $result->link = $channel->getLink();
     foreach ($channel as $item) {
         // Reset the parsed item.
         $parsed_item = array();
         // Move the values to an array as expected by processors.
         $parsed_item['title'] = $item->getTitle();
         $parsed_item['guid'] = $item->getId();
         $parsed_item['url'] = $item->getLink();
         $parsed_item['description'] = $item->getDescription();
         if ($enclosure = $item->getEnclosure()) {
             $parsed_item['enclosures'][] = urldecode($enclosure->url);
         }
         if ($author = $item->getAuthor()) {
             $parsed_item['author_name'] = $author['name'];
         }
         if ($date = $item->getDateModified()) {
             $parsed_item['timestamp'] = $date->getTimestamp();
         }
         $parsed_item['tags'] = $item->getCategories()->getValues();
         $result->items[] = $parsed_item;
     }
     return $result;
 }
Пример #12
0
 /**
  * {@inheritodc}
  */
 public function clear(FeedInterface $feed, array &$context)
 {
     try {
         $this->dispatchEvent(FeedsEvents::INIT_CLEAR, new InitEvent($feed));
         $this->dispatchEvent(FeedsEvents::CLEAR, new ClearEvent($feed));
     } catch (\Exception $exception) {
         // Do nothing yet.
     }
     // Clean up.
     $context['finished'] = $feed->progressClearing();
     if (isset($exception)) {
         $context['finished'] = StateInterface::BATCH_COMPLETE;
     }
     if ($context['finished'] === StateInterface::BATCH_COMPLETE) {
         $feed->finishClear();
         $feed->save();
         $feed->unlock();
     } else {
         $feed->saveStates();
     }
     if (isset($exception)) {
         throw $exception;
     }
 }
Пример #13
0
 protected function unsubscribe(FeedInterface $feed, SubscriptionInterface $subscription = NULL)
 {
     if (!$subscription) {
         return;
     }
     $subscription->unsubscribe();
     $batch = ['title' => t('Unsubscribing from: %title', ['%title' => $feed->label()]), 'init_message' => t('Unsubscribing from: %title', ['%title' => $feed->label()]), 'operations' => [['Drupal\\feeds\\EventSubscriber\\PubSubHubbub::runSubscribeBatch', [$subscription]]], 'progress_message' => t('Unsubscribing: %title', ['%title' => $feed->label()]), 'error_message' => t('An error occored while unsubscribing from %title.', ['%title' => $feed->label()])];
     batch_set($batch);
 }
Пример #14
0
 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()];
 }
Пример #15
0
 /**
  * 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);
 }
Пример #16
0
 /**
  * {@inheritdoc}
  */
 public function getItemCount(FeedInterface $feed)
 {
     return $this->queryFactory->get($this->entityType())->condition('feeds_item.target_id', $feed->id())->count()->execute();
 }
Пример #17
0
 /**
  * {@inheritdoc}
  */
 public function submitFeedForm(array &$form, FormStateInterface $form_state, FeedInterface $feed)
 {
     // We need to store this for later so that we have the feed id.
     $new_fid = reset($form_state->getValue('source'));
     $feed_config = $feed->getConfigurationFor($this);
     // Generate a UUID that maps to this feed for file usage. We can't depend
     // on the feed id since this could be called before an id is assigned.
     $feed_config['usage_id'] = $feed_config['usage_id'] ?: $this->uuid->generate();
     if ($new_fid == $feed_config['fid']) {
         return;
     }
     $this->deleteFile($feed_config['fid'], $feed_config['usage_id']);
     if ($new_fid) {
         $file = $this->fileStorage->load($new_fid);
         $this->fileUsage->add($file, 'feeds', $this->pluginType(), $feed_config['usage_id']);
         $file->setPermanent();
         $file->save();
         $feed_config['fid'] = $new_fid;
         $feed->setSource($file->getFileUri());
     }
     $feed->setConfigurationFor($this, $feed_config);
 }
Пример #18
0
 /**
  * Stub for plugins implementing FeedPluginFormInterface.
  *
  * Most all plugins should get automatic submit handlers from this.
  *
  * @see \Drupal\feeds\Plugin\Type\FeedPluginFormInterface
  */
 public function submitFeedForm(array &$form, array &$form_state, FeedInterface $feed)
 {
     if (isset($form_state['values'][$this->pluginType()])) {
         $feed->setConfigurationFor($this, $form_state['values'][$this->pluginType()]);
     }
 }
Пример #19
0
 /**
  * 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);
     }
 }
Пример #20
0
 /**
  * {@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);
         }
     }
 }
Пример #21
0
 /**
  * Handles an exception during importing.
  *
  * @param \Drupal\feeds\FeedInterface $feed
  *   The feed.
  * @param \Exception $exception
  *   The exception that was thrown.
  *
  * @throws \Exception
  *   Thrown if $exception is not an instance of EmptyFeedException.
  */
 protected function handleException(FeedInterface $feed, \Exception $exception)
 {
     $feed->finishImport();
     if ($exception instanceof EmptyFeedException) {
         return;
     }
     if ($exception instanceof \RuntimeException) {
         drupal_set_message($exception->getMessage(), 'error');
         return;
     }
     throw $exception;
 }
Пример #22
0
 /**
  * {@inheritdoc}
  */
 public function buildFeedForm(array $form, array &$form_state, FeedInterface $feed)
 {
     $feed_config = $feed->getConfigurationFor($this);
     $form['parser']['#tree'] = TRUE;
     $form['parser']['#weight'] = -10;
     $mappings = $this->importer->getMappings();
     // $feeds = $uniques = array();
     // foreach ($mappings as $mapping) {
     //   $feeds[] = check_plain($mapping['source']);
     //   if (!empty($mapping['unique'])) {
     //     $uniques[] = check_plain($mapping['source']);
     //   }
     // }
     // $output = $this->t('Import !csv_files with one or more of these columns: !columns.', array(
     //   '!csv_files' => l($this->t('CSV files'), 'http://en.wikipedia.org/wiki/Comma-separated_values'),
     //   '!columns' => implode(', ', $feeds),
     // ));
     // $items = array();
     // $items[] = format_plural(count($uniques), $this->t('Column <strong>!column</strong> is mandatory and considered unique: only one item per !column value will be created.', array('!column' => implode(', ', $uniques))), $this->t('Columns <strong>!columns</strong> are mandatory and values in these columns are considered unique: only one entry per value in one of these column will be created.', array('!columns' => implode(', ', $uniques))));
     // $items[] = l($this->t('Download a template'), 'import/' . $this->importer->id() . '/template');
     // $form['parser']['help'] = array(
     //   '#prefix' => '<div class="help">',
     //   '#suffix' => '</div>',
     //   'description' => array(
     //     '#prefix' => '<p>',
     //     '#markup' => $output,
     //     '#suffix' => '</p>',
     //   ),
     // 'list' => array(
     //   '#theme' => 'item_list',
     //   '#items' => $items,
     // ),
     // );
     $form['parser']['delimiter'] = array('#type' => 'select', '#title' => $this->t('Delimiter'), '#description' => $this->t('The character that delimits fields in the CSV file.'), '#options' => array(',' => ',', ';' => ';', 'TAB' => 'TAB', '|' => '|', '+' => '+'), '#default_value' => isset($feed_config['delimiter']) ? $feed_config['delimiter'] : ',');
     $form['parser']['no_headers'] = array('#type' => 'checkbox', '#title' => $this->t('No Headers'), '#description' => $this->t('Check if the imported CSV file does not start with a header row. If checked, mapping sources must be named \'0\', \'1\', \'2\' etc.'), '#default_value' => isset($feed_config['no_headers']) ? $feed_config['no_headers'] : 0);
     return $form;
 }
Пример #23
0
 /**
  * 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);
 }
Пример #24
0
 /**
  * {@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;
     }
 }
Пример #25
0
 /**
  * {@inheritdoc}
  */
 public function submitFeedForm(array &$form, FormStateInterface $form_state, FeedInterface $feed)
 {
     $feed->setSource($form_state->getValue('source'));
 }
Пример #26
0
 /**
  * Stub for plugins implementing FeedPluginFormInterface.
  *
  * Most all plugins should get automatic submit handlers from this.
  *
  * @see \Drupal\feeds\Plugin\Type\FeedPluginFormInterface
  */
 public function submitFeedForm(array &$form, FormStateInterface $form_state, FeedInterface $feed)
 {
     $feed->setConfigurationFor($this, $form_state->getValues());
 }