class ResourceFetcher

Same name in other branches
  1. 9 core/modules/media/src/OEmbed/ResourceFetcher.php \Drupal\media\OEmbed\ResourceFetcher
  2. 10 core/modules/media/src/OEmbed/ResourceFetcher.php \Drupal\media\OEmbed\ResourceFetcher
  3. 11.x core/modules/media/src/OEmbed/ResourceFetcher.php \Drupal\media\OEmbed\ResourceFetcher

Fetches and caches oEmbed resources.

Hierarchy

Expanded class hierarchy of ResourceFetcher

1 file declares its use of ResourceFetcher
OEmbedResourceConstraintValidatorTest.php in core/modules/media/tests/src/Kernel/OEmbedResourceConstraintValidatorTest.php
1 string reference to 'ResourceFetcher'
media.services.yml in core/modules/media/media.services.yml
core/modules/media/media.services.yml
1 service uses ResourceFetcher
media.oembed.resource_fetcher in core/modules/media/media.services.yml
Drupal\media\OEmbed\ResourceFetcher

File

core/modules/media/src/OEmbed/ResourceFetcher.php, line 14

Namespace

Drupal\media\OEmbed
View source
class ResourceFetcher implements ResourceFetcherInterface {
    use UseCacheBackendTrait;
    
    /**
     * The HTTP client.
     *
     * @var \GuzzleHttp\Client
     */
    protected $httpClient;
    
    /**
     * The oEmbed provider repository service.
     *
     * @var \Drupal\media\OEmbed\ProviderRepositoryInterface
     */
    protected $providers;
    
    /**
     * Constructs a ResourceFetcher object.
     *
     * @param \GuzzleHttp\ClientInterface $http_client
     *   The HTTP client.
     * @param \Drupal\media\OEmbed\ProviderRepositoryInterface $providers
     *   The oEmbed provider repository service.
     * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
     *   (optional) The cache backend.
     */
    public function __construct(ClientInterface $http_client, ProviderRepositoryInterface $providers, CacheBackendInterface $cache_backend = NULL) {
        $this->httpClient = $http_client;
        $this->providers = $providers;
        $this->cacheBackend = $cache_backend;
        $this->useCaches = isset($cache_backend);
    }
    
    /**
     * {@inheritdoc}
     */
    public function fetchResource($url) {
        $cache_id = "media:oembed_resource:{$url}";
        $cached = $this->cacheGet($cache_id);
        if ($cached) {
            return $this->createResource($cached->data, $url);
        }
        try {
            $response = $this->httpClient
                ->get($url);
        } catch (RequestException $e) {
            throw new ResourceException('Could not retrieve the oEmbed resource.', $url, [], $e);
        }
        list($format) = $response->getHeader('Content-Type');
        $content = (string) $response->getBody();
        if (strstr($format, 'text/xml') || strstr($format, 'application/xml')) {
            $data = $this->parseResourceXml($content, $url);
        }
        elseif (strstr($format, 'text/javascript') || strstr($format, 'application/json')) {
            $data = Json::decode($content);
        }
        else {
            throw new ResourceException('The fetched resource did not have a valid Content-Type header.', $url);
        }
        $this->cacheSet($cache_id, $data);
        return $this->createResource($data, $url);
    }
    
    /**
     * Creates a Resource object from raw resource data.
     *
     * @param array $data
     *   The resource data returned by the provider.
     * @param string $url
     *   The URL of the resource.
     *
     * @return \Drupal\media\OEmbed\Resource
     *   A value object representing the resource.
     *
     * @throws \Drupal\media\OEmbed\ResourceException
     *   If the resource cannot be created.
     */
    protected function createResource(array $data, $url) {
        $data += [
            'title' => NULL,
            'author_name' => NULL,
            'author_url' => NULL,
            'provider_name' => NULL,
            'cache_age' => NULL,
            'thumbnail_url' => NULL,
            'thumbnail_width' => NULL,
            'thumbnail_height' => NULL,
            'width' => NULL,
            'height' => NULL,
            'url' => NULL,
            'html' => NULL,
            'version' => NULL,
        ];
        if ($data['version'] !== '1.0') {
            throw new ResourceException("Resource version must be '1.0'", $url, $data);
        }
        // Prepare the arguments to pass to the factory method.
        $provider = $data['provider_name'] ? $this->providers
            ->get($data['provider_name']) : NULL;
        // The Resource object will validate the data we create it with and throw an
        // exception if anything looks wrong. For better debugging, catch those
        // exceptions and wrap them in a more specific and useful exception.
        try {
            switch ($data['type']) {
                case Resource::TYPE_LINK:
                    return Resource::link($data['url'], $provider, $data['title'], $data['author_name'], $data['author_url'], $data['cache_age'], $data['thumbnail_url'], $data['thumbnail_width'], $data['thumbnail_height']);
                case Resource::TYPE_PHOTO:
                    return Resource::photo($data['url'], $data['width'], $data['height'], $provider, $data['title'], $data['author_name'], $data['author_url'], $data['cache_age'], $data['thumbnail_url'], $data['thumbnail_width'], $data['thumbnail_height']);
                case Resource::TYPE_RICH:
                    return Resource::rich($data['html'], $data['width'], $data['height'], $provider, $data['title'], $data['author_name'], $data['author_url'], $data['cache_age'], $data['thumbnail_url'], $data['thumbnail_width'], $data['thumbnail_height']);
                case Resource::TYPE_VIDEO:
                    return Resource::video($data['html'], $data['width'], $data['height'], $provider, $data['title'], $data['author_name'], $data['author_url'], $data['cache_age'], $data['thumbnail_url'], $data['thumbnail_width'], $data['thumbnail_height']);
                default:
                    throw new ResourceException('Unknown resource type: ' . $data['type'], $url, $data);
            }
        } catch (\InvalidArgumentException $e) {
            throw new ResourceException($e->getMessage(), $url, $data, $e);
        }
    }
    
    /**
     * Parses XML resource data.
     *
     * @param string $data
     *   The raw XML for the resource.
     * @param string $url
     *   The resource URL.
     *
     * @return array
     *   The parsed resource data.
     *
     * @throws \Drupal\media\OEmbed\ResourceException
     *   If the resource data could not be parsed.
     */
    protected function parseResourceXml($data, $url) {
        // Enable userspace error handling.
        $was_using_internal_errors = libxml_use_internal_errors(TRUE);
        libxml_clear_errors();
        $content = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
        // Restore the previous error handling behavior.
        libxml_use_internal_errors($was_using_internal_errors);
        $error = libxml_get_last_error();
        if ($error) {
            libxml_clear_errors();
            throw new ResourceException($error->message, $url);
        }
        elseif ($content === FALSE) {
            throw new ResourceException('The fetched resource could not be parsed.', $url);
        }
        // Convert XML to JSON so that the parsed resource has a consistent array
        // structure, regardless of any XML attributes or quirks of the XML parser.
        $data = Json::encode($content);
        return Json::decode($data);
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
ResourceFetcher::$httpClient protected property The HTTP client.
ResourceFetcher::$providers protected property The oEmbed provider repository service.
ResourceFetcher::createResource protected function Creates a Resource object from raw resource data.
ResourceFetcher::fetchResource public function Fetches an oEmbed resource. Overrides ResourceFetcherInterface::fetchResource
ResourceFetcher::parseResourceXml protected function Parses XML resource data.
ResourceFetcher::__construct public function Constructs a ResourceFetcher object.
UseCacheBackendTrait::$cacheBackend protected property Cache backend instance.
UseCacheBackendTrait::$useCaches protected property Flag whether caches should be used or skipped.
UseCacheBackendTrait::cacheGet protected function Fetches from the cache backend, respecting the use caches flag. 1
UseCacheBackendTrait::cacheSet protected function Stores data in the persistent cache, respecting the use caches flag.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.