class CdnProvider

The "cdn_provider" theme setting.

Plugin annotation

  id = "cdn_provider",
  type = "select",
  title = @Translation("CDN Provider"),
  description = @Translation("Choose the CDN Provider used to load Bootstrap resources."),
  defaultValue = "jsdelivr",
  empty_option = @Translation("None (compile locally)"),
  empty_value = "",
  weight = -1,
  groups = {
    "cdn" = @Translation("CDN (Content Delivery Network)"),
    "cdn_provider" = false,
  options = { },


Expanded class hierarchy of CdnProvider

Related topics


class CdnProvider extends CdnProviderBase {

   * {@inheritdoc}
  public function alterForm(array &$form, FormStateInterface $form_state, $form_id = NULL) {
    parent::alterForm($form, $form_state, $form_id);

    // Allow the provider to participate.
    if ($this->provider instanceof FormInterface) {
      $this->provider->alterForm($form, $form_state);

   * {@inheritdoc}
  public function alterFormElement(Element $form, FormStateInterface $form_state, $form_id = NULL) {
    // Wrap the default group so it can be replaced via AJAX.
    $group = $this->getGroupElement($form, $form_state);
    $group->setProperty('prefix', '<div id="cdn-providers">');
    $group->setProperty('suffix', '</div>');

    // Set available CDN Providers.
    $setting = $this->setCdnProvidersAjax($this->getSettingElement($form, $form_state));
    $setting->setProperty('options', array_map(function(ProviderInterface $provider) {
      return $provider->getLabel();
    }, $this->theme->getCdnProviders()));

    // Add the CDN Provider description.
    $provider = $this->getProvider();
    $description = $provider->getDescription();
    $group->description = [
      '#access' => AccessResultAllowed::allowedIf(!empty((string) $description) && !($provider instanceof Broken)),
      '#type' => 'container',
      '#theme_wrappers' => ['container__help_block'],
      0 => ['#markup' => $description],

    // Add CDN Provider cache reset functionality.
    $group->cache = [
      '#access' => AccessResultAllowed::allowedIf(!($provider instanceof Broken)),
      '#type' => 'details',
      '#title' => $this->t('Advanced Cache'),
      '#description' => $this->t('All @provider data is intelligently and automatically cached using the various settings below. This allows the @provider data to persist through cache rebuilds. This data will invalidate and rebuild automatically, however a manual reset can be invoked below.', [
        '@provider' => $provider->getPluginId() === 'custom' ? $this->t('CDN Provider') : $provider->getLabel(),
      '#weight' => 1000,

    $ttl_settings = [

    // Because these settings are used for all providers, any current value set
    // in the input array is a result of a provider switch via AJAX. Go ahead
    // and unset the value from the current form state and then add the setting
    // to the form.
    $input = $form_state->getUserInput();
    $values = $form_state->getValues();
    foreach ($ttl_settings as $ttl_setting) {
      if (!empty($input['_triggering_element_name']) && $input['_triggering_element_name'] === 'cdn_provider') {
        unset($input[$ttl_setting], $values[$ttl_setting]);
      $this->theme->getSettingPlugin($ttl_setting)->alterForm($form->getArray(), $form_state);

    $group->cache->reset = $this->setCdnProvidersAjax(Element::createStandalone([
      '#weight' => 100,
      '#type' => 'submit',
      '#description' => $this->t('Note: this will not reset any cached HTTP requests; see the "Advanced" section.'),
      '#value' => $this->t('Reset @provider Cache', [
        '@provider' => $provider->getLabel(),
      '#submit' => [
        [get_class($this), 'submitResetProviderCache'],

    // Intercept possible manual import of API data via AJAX callback.
    // @todo Import functionality is deprecated, remove in a future release.
    $this->importProviderData($group, $form_state);

   * {@inheritdoc}
  public static function submitForm(array &$form, FormStateInterface $form_state) {
    parent::submitForm($form, $form_state);
    $theme = SystemThemeSettings::getTheme(Element::create($form), $form_state);
    $provider = ProviderManager::load($theme, $form_state->getValue('cdn_provider'));
    if ($provider instanceof FormInterface) {
      $provider->submitForm($form, $form_state);

   * Submit callback for resetting CDN Provider cache.
   * @param array $form
   *   Nested array of form elements that comprise the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
  public static function submitResetProviderCache(array $form, FormStateInterface $form_state) {
    $theme = SystemThemeSettings::getTheme(Element::create($form), $form_state);
    $provider = ProviderManager::load($theme, $form_state->getValue('cdn_provider', $theme->getSetting('cdn_provider')));

   * {@inheritdoc}
  public static function validateFormElement(Element $form, FormStateInterface $form_state) {
    parent::validateFormElement($form, $form_state);
    $theme = SystemThemeSettings::getTheme($form, $form_state);
    $provider = ProviderManager::load($theme, $form_state->getValue('cdn_provider'));

    // Validate the provider.
    if (!($provider instanceof Broken)) {
      $cdnVersion = $form_state->getValue('cdn_version', $theme->getSetting('cdn_version', Bootstrap::FRAMEWORK_VERSION));
      $cdnTheme = $form_state->getValue('cdn_theme', $theme->getSetting('cdn_theme'));
      $assets = $provider->getCdnAssets($cdnVersion, $cdnTheme);

      // Now validate that each asset is reachable.
      $unreachable = [];
      foreach ($assets->toArray() as $asset) {
        $url = $asset->getUrl();
        if (!Bootstrap::checkUrlIsReachable($url)) {
          $unreachable[] = Link::fromTextAndUrl($url, Url::fromUri($url)->setOption('attributes', ['target' => '_blank']));

      if ($unreachable) {
        $form_state->setErrorByName('cdn_provider', t('Unable to reach the following @provider assets: <ul><li>@unreachable</li>', [
          '@provider' => $provider->getLabel(),
          '@unreachable' => Markup::create(implode('</li><li>', $unreachable)),

      // Check for exceptions (API HTTP request errors).
      if (static::checkCdnExceptions($provider)) {
        $form_state->setErrorByName('cdn_provider', t('Unable to use @provider assets. Please choose a different CDN Provider.', [
          '@provider' => $provider->getLabel(),

    if ($provider instanceof FormInterface) {
      $provider->validateFormElement($form, $form_state);

   * Imports data for a provider that was manually uploaded in theme settings.
   * @param \Drupal\bootstrap\Utility\Element $group
   *   The setting group Element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @todo Import functionality is deprecated, remove in a future release.
  protected function importProviderData(Element $group, FormStateInterface $form_state) {
    if ($form_state->getValue('clicked_button') === t('Save provider data')->render()) {
      $provider_path = ProviderManager::FILE_PATH;
      file_prepare_directory($provider_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);

      $provider = $form_state->getValue('cdn_provider', $this->theme->getSetting('cdn_provider'));
      $file = "$provider_path/$provider.json";

      if ($import_data = $form_state->getValue('cdn_provider_import_data', FALSE)) {
        file_unmanaged_save_data($import_data, $file, FILE_EXISTS_REPLACE);
      elseif ($file && file_exists($file)) {

      // Clear the cached definitions so they can get rebuilt.
      $providerManager = new ProviderManager($this->theme);

    $provider = $this->getProvider();
    $plugin_id = Html::cleanCssIdentifier($provider->getPluginId());

    // To avoid triggering unnecessary deprecation messages, extract these
    // values from the provider definition directly.
    // @todo Import functionality is deprecated, remove in a future release.
    $definition = $provider->getPluginDefinition();
    $hasError = !empty($definition['error']);
    $isImported = !empty($definition['imported']);

    // Indicate there was an error retrieving the provider's API data.
    if ($hasError || $isImported) {
      if ($isImported) {
      if ($hasError) {
        // Now a deprecation message can be shown as the provider clearly is
        // using the outdated "process definition" method of providing assets.
        $description_label = $this->t('ERROR');
        $description = $this->t('Unable to reach or parse the data provided by the @title API. Ensure the server this website is hosted on is able to initiate HTTP requests. If the request consistently fails, it is likely that there are certain PHP functions that have been disabled by the hosting provider for security reasons. It is possible to manually copy and paste the contents of the following URL into the "Imported @title data" section below.<br /><br /><a href=":provider_api" target="_blank">:provider_api</a>.', [
          '@title' => $provider->getLabel(),
          ':provider_api' => $provider->getApi(),
        $group->error = [
          '#markup' => '<div class="alert alert-danger messages error"><strong>' . $description_label . ':</strong> ' . $description . '</div>',
          '#weight' => -20,

      $group->import = [
        '#type' => 'details',
        '#title' => t('Imported @title data', ['@title' => $provider->getLabel()]),
        '#description' => t('The provider will attempt to parse the data entered here each time it is saved. If no data has been entered, any saved files associated with this provider will be removed and the provider will again attempt to request the API data normally through the following URL: <a href=":provider_api" target="_blank">:provider_api</a>.', [
          ':provider_api' => $provider->getPluginDefinition()['api'],
        '#weight' => 10,
        '#open' => FALSE,

      $group->import->cdn_provider_import_data = [
        '#type' => 'textarea',
        '#default_value' => file_exists(ProviderManager::FILE_PATH . '/' . $plugin_id . '.json') ? file_get_contents(ProviderManager::FILE_PATH . '/' . $plugin_id . '.json') : NULL,

      $group->import->submit = $this->setCdnProvidersAjax([
        '#type' => 'submit',
        '#value' => t('Save provider data'),
        '#executes_submit_callback' => FALSE,



Contains filters are case sensitive
Name Modifiers Type Description
CdnProvider::alterForm public function The alter method to store the code. Overrides CdnProviderBase::alterForm
CdnProvider::alterFormElement public function The alter method to store the code. Overrides SettingBase::alterFormElement
CdnProvider::importProviderData protected function Imports data for a provider that was manually uploaded in theme settings.
CdnProvider::submitForm public static function Form submission handler. Overrides SettingBase::submitForm
CdnProvider::submitResetProviderCache public static function Submit callback for resetting CDN Provider cache.
CdnProvider::validateFormElement public static function Form validation handler. Overrides SettingBase::validateFormElement
CdnProviderBase::$provider protected property The active provider based on form value or theme setting.
CdnProviderBase::ajaxCdnProvidersCallback public static function AJAX callback for reloading CDN Providers.
CdnProviderBase::checkCdnExceptions protected static function Handles any CDN Provider exceptions that may have been thrown.
CdnProviderBase::getCacheTags public function The cache tags associated with this object. Overrides SettingBase::getCacheTags
CdnProviderBase::getProvider protected function Retrieves the active CDN Provider.
CdnProviderBase::setCdnProvidersAjax protected function Sets the #ajax property to rebuild the entire CDN Providers container.
FormAutoloadFixTrait::formAutoloadFix public static function Adds the autoload fix include file to the form state.
PluginBase::$theme protected property The currently set theme object.
PluginBase::__construct public function
SettingBase::$autoUserInterface public static property
SettingBase::access public function Indicates whether a setting is accessible. Overrides SettingInterface::access
SettingBase::autoCreateFormElement public function Indicates whether a form element should be created automatically. Overrides SettingInterface::autoCreateFormElement
SettingBase::drupalSettings public function Determines whether a theme setting should added to drupalSettings. Overrides SettingInterface::drupalSettings
SettingBase::getDefaultValue public function Retrieves the setting's default value. Overrides SettingInterface::getDefaultValue
SettingBase::getDescription public function Retrieves the setting's description, if any. Overrides SettingInterface::getDescription
SettingBase::getElement Deprecated public function Overrides SettingInterface::getElement
SettingBase::getElementProperties public function Retrieves all the form properties from the setting definition.
SettingBase::getGroup Deprecated public function Overrides SettingInterface::getGroup
SettingBase::getGroupElement public function Retrieves the group form element the setting belongs to. Overrides SettingInterface::getGroupElement
SettingBase::getGroups public function Retrieves the setting's groups. Overrides SettingInterface::getGroups
SettingBase::getOptions public function Retrieves the settings options, if set. Overrides SettingInterface::getOptions
SettingBase::getSettingElement public function Retrieves the form element for the setting. Overrides SettingInterface::getSettingElement
SettingBase::getSettingValue protected function Retrieves the setting value used to populate the form.
SettingBase::getTitle public function Retrieves the setting's human-readable title. Overrides SettingInterface::getTitle
SettingBase::processDeprecatedValues public function Retrieves the value from other deprecated settings. Overrides SettingInterface::processDeprecatedValues
SettingBase::submitFormElement public static function Form submission handler. Overrides FormInterface::submitFormElement
SettingBase::validateForm public static function Form validation handler. Overrides FormInterface::validateForm