Provide easier way to override HttpFetcher::get() for passing extra request options

Created on 11 November 2023, about 1 year ago
Updated 18 November 2023, about 1 year ago

Problem/Motivation

In Drupal\feeds\Feeds\Fetcher\HttpFetcher::get() a http request gets made using Guzzle. The request gets made with the following line:

$response = $this->client->getAsync($url, $options)->wait();

Sometimes you want to set extra options for the request to be made, there are a lot of these available: https://docs.guzzlephp.org/en/stable/request-options.html

Right now a class must extend HttpFetcher and override the whole get() method just to specify an extra option. So this causes a lot of code duplication.

Proposed resolution

There is more than one way to allow extra options to be set. The easiest solution is to specify an additional parameter for the get() method called $options. This way, subclasses could still override the get() method if they want, but then they only have to specify the extra options they want and handle the rest of via the parent:

use Drupal\feeds\Feeds\Fetcher\HttpFetcher;

class MyHttpFetcher extends HttpFetcher {

  /**
   * {@inheritdoc}
   */
  protected function get($url, $sink, $cache_key = FALSE, array $options = []) {
    $options += [
      'auth' => ['**user**','**pass**','digest'],
    ];
    return parent::get($url, $sink, $cache_key, $options);
  }

}

Or the subclass can add the extra option by calling the get() method themselves somewhere. For example, by overriding the whole fetch() method:

use Drupal\feeds\Exception\EmptyFeedException;
use Drupal\feeds\FeedInterface;
use Drupal\feeds\Feeds\Fetcher\HttpFetcher;
use Drupal\feeds\Result\HttpFetcherResult;
use Drupal\feeds\StateInterface;
use Symfony\Component\HttpFoundation\Response;

class MyHttpFetcher extends HttpFetcher {

  /**
   * {@inheritdoc}
   */
  public function fetch(FeedInterface $feed, StateInterface $state) {
    $sink = $this->feedsFileSystem->tempnam($feed, 'http_fetcher_');

    // Get cache key if caching is enabled.
    $cache_key = $this->useCache() ? $this->getCacheKey($feed) : FALSE;

    $response = $this->get($feed->getSource(), $sink, $cache_key, [
      'auth' => ['**user**','**pass**','digest'],
    ]);

    // 304, nothing to see here.
    if ($response->getStatusCode() == Response::HTTP_NOT_MODIFIED) {
      $state->setMessage($this->t('The feed has not been updated.'));
      throw new EmptyFeedException();
    }

    return new HttpFetcherResult($sink, $response->getHeaders(), $this->fileSystem);
  }

}

This looks less ideal though, as you are then still copying the contents of a whole method.

Remaining tasks

User interface changes

API changes

Data model changes

✨ Feature request
Status

Fixed

Version

3.0

Component

Code

Created by

πŸ‡³πŸ‡±Netherlands megachriz

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Production build 0.71.5 2024