You are here

final class CdnWarmer in Warmer 2.x

Same name and namespace in other branches
  1. 8 modules/warmer_cdn/src/Plugin/warmer/CdnWarmer.php \Drupal\warmer_cdn\Plugin\warmer\CdnWarmer

The cache warmer for the built-in entity cache.

Plugin annotation


@Warmer(
  id = "cdn",
  label = @Translation("CDN"),
  description = @Translation("Executes HTTP requests to warm the edge caches. It is useful without a CDN as well, as it will also warm Varnish and Page Cache.")
)

Hierarchy

Expanded class hierarchy of CdnWarmer

File

modules/warmer_cdn/src/Plugin/warmer/CdnWarmer.php, line 23

Namespace

Drupal\warmer_cdn\Plugin\warmer
View source
final class CdnWarmer extends WarmerPluginBase {
  use UserInputParserTrait;
  use LoggerChannelTrait;

  /**
   * The HTTP client.
   *
   * @var \GuzzleHttp\ClientInterface
   */
  private $httpClient;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    assert($instance instanceof CdnWarmer);
    $instance
      ->setHttpClient($container
      ->get('http_client'));
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function loadMultiple(array $ids = []) {

    // Ensure items are fully loaded URLs.
    $urls = array_map([
      $this,
      'resolveUri',
    ], $ids);
    return array_filter($urls, [
      UrlHelper::class,
      'isValid',
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function warmMultiple(array $items = []) {
    $headers = $this
      ->parseHeaders();
    $verify = (bool) $this
      ->getConfiguration()['verify'];
    $max_concurrent_requests = (int) $this
      ->getConfiguration()['maxConcurrentRequests'];

    // Default to one request at a time.
    if ($max_concurrent_requests <= 0) {
      $max_concurrent_requests = 1;
    }
    $promises = [];
    $success = 0;
    foreach ($items as $key => $url) {

      // Fire async request.
      $promises[] = $this->httpClient
        ->requestAsync('GET', $url, [
        'headers' => $headers,
        'verify' => $verify,
      ])
        ->then(function (ResponseInterface $response) use (&$success) {
        if ($response
          ->getStatusCode() < 399) {
          $success++;
        }
      }, function (\Exception $e) {
        $this
          ->getLogger('warmer')
          ->warning($e
          ->getMessage());
      });

      // Wait for all fired requests if max number is reached.
      $item_keys = array_keys($items);
      if ($key % $max_concurrent_requests == 0 || $key == end($item_keys)) {
        \GuzzleHttp\Promise\all($promises)
          ->wait();
        $promises = [];
      }
    }
    return $success;
  }

  /**
   * Parses the configuration to extract the headers to inject in every request.
   *
   * @return array
   *   The array of headers as expected by Guzzle.
   */
  private function parseHeaders() {
    $configuration = $this
      ->getConfiguration();
    $header_lines = $configuration['headers'];

    // Parse headers.
    return array_reduce($header_lines, function ($carry, $header_line) {
      list($name, $value_line) = array_map('trim', explode(':', $header_line));
      $values = array_map('trim', explode(';', $value_line));
      $values = array_filter($values);
      $values = count($values) === 1 ? reset($values) : $values;
      $carry[$name] = $values;
      return $carry;
    }, []);
  }

  /**
   * {@inheritdoc}
   */
  public function buildIdsBatch($cursor) {

    // Parse the sitemaps and extract the URLs.
    $config = $this
      ->getConfiguration();
    $urls = empty($config['urls']) ? [] : $config['urls'];
    $cursor_position = is_null($cursor) ? -1 : array_search($cursor, $urls);
    if ($cursor_position === FALSE) {
      return [];
    }
    return array_slice($urls, $cursor_position + 1, (int) $this
      ->getBatchSize());
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
    parent::validateConfigurationForm($form, $form_state);
    $this
      ->validateHeaders($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function addMoreConfigurationFormElements(array $form, SubformStateInterface $form_state) {
    $configuration = $this
      ->getConfiguration();
    $form['urls'] = [
      '#type' => 'textarea',
      '#title' => $this
        ->t('URLs'),
      '#description' => $this
        ->t('Enter the list of URLs. One on each line. Examples: https://example.org/foo/bar, /foo/bar.'),
      '#default_value' => empty($configuration['urls']) ? '' : implode("\n", $configuration['urls']),
    ];
    $form['headers'] = [
      '#type' => 'textarea',
      '#title' => $this
        ->t('Headers'),
      '#description' => $this
        ->t('Specific headers to use when making HTTP requests. Format: <code>Header-Name: value1; value2</code>'),
      '#default_value' => empty($configuration['headers']) ? '' : implode("\n", $configuration['headers']),
    ];
    $form['verify'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Enable SSL verification'),
      '#description' => $this
        ->t('Enable SSL verification. Recommended to keep it checked for security reasons.'),
      '#default_value' => isset($configuration['verify']) ? $configuration['verify'] : TRUE,
    ];
    $form['maxConcurrentRequests'] = [
      '#type' => 'number',
      '#min' => 1,
      '#step' => 1,
      '#title' => $this
        ->t('Maximum number of concurrent Requests.'),
      '#description' => $this
        ->t('The maximum number of concurrent requests.'),
      '#default_value' => empty($configuration['maxConcurrentRequests']) ? 10 : $configuration['maxConcurrentRequests'],
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    $configuration = $form_state
      ->getValues() + $this->configuration;
    $configuration['urls'] = $this
      ->extractTextarea($configuration, 'urls');
    $configuration['headers'] = $this
      ->extractTextarea($configuration, 'headers');
    $this
      ->setConfiguration($configuration);
  }

  /**
   * Set the HTTP client.
   *
   * @param \GuzzleHttp\ClientInterface $client
   *   The client.
   */
  public function setHttpClient(ClientInterface $client) {
    $this->httpClient = $client;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'maxConcurrentRequests' => 10,
    ] + parent::defaultConfiguration();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CdnWarmer::$httpClient private property The HTTP client.
CdnWarmer::addMoreConfigurationFormElements public function Adds additional form elements to the configuration form. Overrides WarmerInterface::addMoreConfigurationFormElements
CdnWarmer::buildIdsBatch public function Builds the next batch of IDs based on a position cursor. Overrides WarmerInterface::buildIdsBatch
CdnWarmer::create public static function Creates an instance of the plugin. Overrides WarmerPluginBase::create
CdnWarmer::defaultConfiguration public function Gets default configuration for this plugin. Overrides WarmerPluginBase::defaultConfiguration
CdnWarmer::loadMultiple public function Loads multiple items based on their IDs. Overrides WarmerInterface::loadMultiple
CdnWarmer::parseHeaders private function Parses the configuration to extract the headers to inject in every request.
CdnWarmer::setHttpClient public function Set the HTTP client.
CdnWarmer::submitConfigurationForm public function Form submission handler. Overrides WarmerPluginBase::submitConfigurationForm
CdnWarmer::validateConfigurationForm public function Form validation handler. Overrides WarmerPluginBase::validateConfigurationForm
CdnWarmer::warmMultiple public function Warms multiple items. Overrides WarmerInterface::warmMultiple
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 27
MessengerTrait::messenger public function Gets the messenger. 27
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 2
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UserInputParserTrait::extractTextarea private function Parses the string under $key in the $values collection.
UserInputParserTrait::resolveUri private function Resolves a URI into a fully loaded URL.
UserInputParserTrait::validateHeaders private function Validate the input for the headers.
WarmerPluginBase::$state protected property The state service.
WarmerPluginBase::$time protected property The time service.
WarmerPluginBase::buildConfigurationForm final public function Form constructor. Overrides PluginFormInterface::buildConfigurationForm
WarmerPluginBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies
WarmerPluginBase::getBatchSize public function Returns the batch size for the warming operation. Overrides WarmerInterface::getBatchSize
WarmerPluginBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
WarmerPluginBase::getFrequency public function Returns the frequency for the warming operation. Overrides WarmerInterface::getFrequency
WarmerPluginBase::isActive public function Checks if the plugin should warm in this particular moment. Overrides WarmerInterface::isActive
WarmerPluginBase::markAsEnqueued public function Marks a warmer as enqueued. Overrides WarmerInterface::markAsEnqueued
WarmerPluginBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration
WarmerPluginBase::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides PluginBase::__construct