Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / media / src / Plugin / Validation / Constraint / OEmbedResourceConstraintValidator.php
diff --git a/web/core/modules/media/src/Plugin/Validation/Constraint/OEmbedResourceConstraintValidator.php b/web/core/modules/media/src/Plugin/Validation/Constraint/OEmbedResourceConstraintValidator.php
new file mode 100644 (file)
index 0000000..99f6fab
--- /dev/null
@@ -0,0 +1,144 @@
+<?php
+
+namespace Drupal\media\Plugin\Validation\Constraint;
+
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Logger\LoggerChannelFactoryInterface;
+use Drupal\media\OEmbed\ProviderException;
+use Drupal\media\OEmbed\ResourceException;
+use Drupal\media\OEmbed\ResourceFetcherInterface;
+use Drupal\media\OEmbed\UrlResolverInterface;
+use Drupal\media\Plugin\media\Source\OEmbedInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+
+/**
+ * Validates oEmbed resource URLs.
+ *
+ * @internal
+ *   This is an internal part of the oEmbed system and should only be used by
+ *   oEmbed-related code in Drupal core.
+ */
+class OEmbedResourceConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
+
+  /**
+   * The oEmbed URL resolver service.
+   *
+   * @var \Drupal\media\OEmbed\UrlResolverInterface
+   */
+  protected $urlResolver;
+
+  /**
+   * The resource fetcher service.
+   *
+   * @var \Drupal\media\OEmbed\ResourceFetcherInterface
+   */
+  protected $resourceFetcher;
+
+  /**
+   * The logger service.
+   *
+   * @var \Drupal\Core\Logger\LoggerChannelInterface
+   */
+  protected $logger;
+
+  /**
+   * Constructs a new OEmbedResourceConstraintValidator.
+   *
+   * @param \Drupal\media\OEmbed\UrlResolverInterface $url_resolver
+   *   The oEmbed URL resolver service.
+   * @param \Drupal\media\OEmbed\ResourceFetcherInterface $resource_fetcher
+   *   The resource fetcher service.
+   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
+   *   The logger service.
+   */
+  public function __construct(UrlResolverInterface $url_resolver, ResourceFetcherInterface $resource_fetcher, LoggerChannelFactoryInterface $logger_factory) {
+    $this->urlResolver = $url_resolver;
+    $this->resourceFetcher = $resource_fetcher;
+    $this->logger = $logger_factory->get('media');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('media.oembed.url_resolver'),
+      $container->get('media.oembed.resource_fetcher'),
+      $container->get('logger.factory')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate($value, Constraint $constraint) {
+    /** @var \Drupal\media\MediaInterface $media */
+    $media = $value->getEntity();
+    /** @var \Drupal\media\Plugin\media\Source\OEmbedInterface $source */
+    $source = $media->getSource();
+
+    if (!($source instanceof OEmbedInterface)) {
+      throw new \LogicException('Media source must implement ' . OEmbedInterface::class);
+    }
+    $url = $source->getSourceFieldValue($media);
+
+    // Ensure that the URL matches a provider.
+    try {
+      $provider = $this->urlResolver->getProviderByUrl($url);
+    }
+    catch (ResourceException $e) {
+      $this->handleException($e, $constraint->unknownProviderMessage);
+      return;
+    }
+    catch (ProviderException $e) {
+      $this->handleException($e, $constraint->providerErrorMessage);
+      return;
+    }
+
+    // Ensure that the provider is allowed.
+    if (!in_array($provider->getName(), $source->getProviders(), TRUE)) {
+      $this->context->addViolation($constraint->disallowedProviderMessage, [
+        '@name' => $provider->getName(),
+      ]);
+      return;
+    }
+
+    // Verify that resource fetching works, because some URLs might match
+    // the schemes but don't support oEmbed.
+    try {
+      $endpoints = $provider->getEndpoints();
+      $resource_url = reset($endpoints)->buildResourceUrl($url);
+      $this->resourceFetcher->fetchResource($resource_url);
+    }
+    catch (ResourceException $e) {
+      $this->handleException($e, $constraint->invalidResourceMessage);
+    }
+  }
+
+  /**
+   * Handles exceptions that occur during validation.
+   *
+   * @param \Exception $e
+   *   The caught exception.
+   * @param string $error_message
+   *   (optional) The error message to set as a constraint violation.
+   */
+  protected function handleException(\Exception $e, $error_message = NULL) {
+    if ($error_message) {
+      $this->context->addViolation($error_message);
+    }
+
+    // The oEmbed system makes heavy use of exception wrapping, so log the
+    // entire exception chain to help with troubleshooting.
+    do {
+      // @todo If $e is a ProviderException or ResourceException, log additional
+      // debugging information contained in those exceptions in
+      // https://www.drupal.org/project/drupal/issues/2972846.
+      $this->logger->error($e->getMessage());
+      $e = $e->getPrevious();
+    } while ($e);
+  }
+
+}