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