91c7ac36ed8573ad1c9103a5ced757419aa240a8
[yaffs-website] / web / core / modules / aggregator / src / Plugin / aggregator / fetcher / DefaultFetcher.php
1 <?php
2
3 namespace Drupal\aggregator\Plugin\aggregator\fetcher;
4
5 use Drupal\aggregator\Plugin\FetcherInterface;
6 use Drupal\aggregator\FeedInterface;
7 use Drupal\Component\Datetime\DateTimePlus;
8 use Drupal\Core\Http\ClientFactory;
9 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
10 use GuzzleHttp\Exception\RequestException;
11 use GuzzleHttp\Psr7\Request;
12 use Psr\Http\Message\RequestInterface;
13 use Psr\Http\Message\ResponseInterface;
14 use Psr\Http\Message\UriInterface;
15 use Psr\Log\LoggerInterface;
16 use Symfony\Component\DependencyInjection\ContainerInterface;
17
18 /**
19  * Defines a default fetcher implementation.
20  *
21  * Uses the http_client service to download the feed.
22  *
23  * @AggregatorFetcher(
24  *   id = "aggregator",
25  *   title = @Translation("Default fetcher"),
26  *   description = @Translation("Downloads data from a URL using Drupal's HTTP request handler.")
27  * )
28  */
29 class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterface {
30
31   /**
32    * The HTTP client to fetch the feed data with.
33    *
34    * @var \Drupal\Core\Http\ClientFactory
35    */
36   protected $httpClientFactory;
37
38   /**
39    * A logger instance.
40    *
41    * @var \Psr\Log\LoggerInterface
42    */
43   protected $logger;
44
45   /**
46    * Constructs a DefaultFetcher object.
47    *
48    * @param \Drupal\Core\Http\ClientFactory $http_client_factory
49    *   A Guzzle client object.
50    * @param \Psr\Log\LoggerInterface $logger
51    *   A logger instance.
52    */
53   public function __construct(ClientFactory $http_client_factory, LoggerInterface $logger) {
54     $this->httpClientFactory = $http_client_factory;
55     $this->logger = $logger;
56   }
57
58   /**
59    * {@inheritdoc}
60    */
61   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
62     return new static(
63       $container->get('http_client_factory'),
64       $container->get('logger.factory')->get('aggregator')
65     );
66   }
67
68   /**
69    * {@inheritdoc}
70    */
71   public function fetch(FeedInterface $feed) {
72     $request = new Request('GET', $feed->getUrl());
73     $feed->source_string = FALSE;
74
75     // Generate conditional GET headers.
76     if ($feed->getEtag()) {
77       $request = $request->withAddedHeader('If-None-Match', $feed->getEtag());
78     }
79     if ($feed->getLastModified()) {
80       $request = $request->withAddedHeader('If-Modified-Since', gmdate(DateTimePlus::RFC7231, $feed->getLastModified()));
81     }
82
83     try {
84
85       /** @var \Psr\Http\Message\UriInterface $actual_uri */
86       $actual_uri = NULL;
87       $response = $this->httpClientFactory->fromOptions(['allow_redirects' => [
88         'on_redirect' => function(RequestInterface $request, ResponseInterface $response, UriInterface $uri) use (&$actual_uri) {
89           $actual_uri = (string) $uri;
90         }
91       ]])->send($request);
92
93       // In case of a 304 Not Modified, there is no new content, so return
94       // FALSE.
95       if ($response->getStatusCode() == 304) {
96         return FALSE;
97       }
98
99       $feed->source_string = (string) $response->getBody();
100       if ($response->hasHeader('ETag')) {
101         $feed->setEtag($response->getHeaderLine('ETag'));
102       }
103       if ($response->hasHeader('Last-Modified')) {
104         $feed->setLastModified(strtotime($response->getHeaderLine('Last-Modified')));
105       }
106       $feed->http_headers = $response->getHeaders();
107
108       // Update the feed URL in case of a 301 redirect.
109       if ($actual_uri && $actual_uri !== $feed->getUrl()) {
110         $feed->setUrl($actual_uri);
111       }
112       return TRUE;
113     }
114     catch (RequestException $e) {
115       $this->logger->warning('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]);
116       drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]), 'warning');
117       return FALSE;
118     }
119   }
120
121 }