You are here

class ThemeSettings in Express 8

Provides a configuration API wrapper for runtime merged theme settings.

This is a wrapper around theme_get_setting() since it does not inherit base theme config nor handle default/overridden values very well.

Hierarchy

Expanded class hierarchy of ThemeSettings

File

themes/contrib/bootstrap/src/ThemeSettings.php, line 22
Contains \Drupal\bootstrap\ThemeSettings.

Namespace

Drupal\bootstrap
View source
class ThemeSettings extends Config {

  /**
   * The default settings.
   *
   * @var array
   */
  protected $defaults;

  /**
   * The current theme object.
   *
   * @var \Drupal\bootstrap\Theme
   */
  protected $theme;

  /**
   * {@inheritdoc}
   */
  public function __construct(Theme $theme) {
    parent::__construct($theme
      ->getName() . '.settings', \Drupal::service('config.storage'), \Drupal::service('event_dispatcher'), \Drupal::service('config.typed'));
    $this->theme = $theme;

    // Retrieve cache.
    $cache = $theme
      ->getCache('settings');

    // Use cached settings.
    if ($defaults = $cache
      ->get('defaults')) {
      $this->defaults = $defaults;
      $this
        ->initWithData($cache
        ->get('data', []));
      return;
    }

    // Retrieve the global settings from configuration.
    $this->defaults = \Drupal::config('system.theme.global')
      ->get();

    // Retrieve the theme setting plugin discovery defaults (code).
    foreach ($theme
      ->getSettingPlugin() as $name => $setting) {
      $this->defaults[$name] = $setting
        ->getDefaultValue();
    }

    // Retrieve the theme ancestry.
    $ancestry = $theme
      ->getAncestry();

    // Remove the active theme from the ancestry.
    $active_theme = array_pop($ancestry);

    // Iterate and merge all ancestor theme config into the defaults.
    foreach ($ancestry as $ancestor) {
      $this->defaults = NestedArray::mergeDeepArray([
        $this->defaults,
        $this
          ->getThemeConfig($ancestor),
      ], TRUE);
    }

    // Merge the active theme config.
    $this
      ->initWithData($this
      ->getThemeConfig($active_theme, TRUE));

    // Cache the data and defaults.
    $cache
      ->set('data', $this->data);
    $cache
      ->set('defaults', $this->defaults);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    return [
      'rendered',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function get($key = '') {
    if (empty($key)) {
      return NestedArray::mergeDeepArray([
        $this->defaults,
        $this->data,
      ], TRUE);
    }
    else {
      $value = parent::get($key);
      if (!isset($value)) {
        $value = $this
          ->getOriginal($key);
      }
    }
    return $value;
  }

  /**
   * {@inheritdoc}
   */
  public function getOriginal($key = '', $apply_overrides = TRUE) {
    $original_data = $this->defaults;
    if ($apply_overrides) {

      // Apply overrides.
      if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
        $original_data = NestedArray::mergeDeepArray(array(
          $original_data,
          $this->moduleOverrides,
        ), TRUE);
      }
      if (isset($this->settingsOverrides) && is_array($this->settingsOverrides)) {
        $original_data = NestedArray::mergeDeepArray(array(
          $original_data,
          $this->settingsOverrides,
        ), TRUE);
      }
    }
    if (empty($key)) {
      return $original_data;
    }
    else {
      $parts = explode('.', $key);
      if (count($parts) == 1) {
        return isset($original_data[$key]) ? $original_data[$key] : NULL;
      }
      else {
        $value = NestedArray::getValue($original_data, $parts, $key_exists);
        return $key_exists ? $value : NULL;
      }
    }
  }

  /**
   * Retrieves a specific theme's stored config settings.
   *
   * @param \Drupal\bootstrap\Theme $theme
   *   A theme object.
   * @param bool $active_theme
   *   Flag indicating whether or not $theme is the active theme.
   *
   * @return array
   *   A array diff of overridden config theme settings.
   */
  public function getThemeConfig(Theme $theme, $active_theme = FALSE) {
    $config = new \Drupal\Core\Theme\ThemeSettings($theme
      ->getName());

    // Retrieve configured theme-specific settings, if any.
    try {
      if ($theme_settings = \Drupal::config($theme
        ->getName() . '.settings')
        ->get()) {

        // Remove schemas if not the active theme.
        if (!$active_theme) {
          unset($theme_settings['schemas']);
        }
        $config
          ->merge($theme_settings);
      }
    } catch (StorageException $e) {
    }

    // If the theme does not support a particular feature, override the
    // global setting and set the value to NULL.
    $info = $theme
      ->getInfo();
    if (!empty($info['features'])) {
      foreach (_system_default_theme_features() as $feature) {
        if (!in_array($feature, $info['features'])) {
          $config
            ->set('features.' . $feature, NULL);
        }
      }
    }

    // Generate the path to the logo image.
    if ($config
      ->get('features.logo')) {
      $logo_url = FALSE;
      foreach ([
        'svg',
        'png',
        'jpg',
      ] as $type) {
        if (file_exists($theme
          ->getPath() . "/logo.{$type}")) {
          $logo_url = file_create_url($theme
            ->getPath() . "/logo.{$type}");
          break;
        }
      }
      if ($config
        ->get('logo.use_default') && $logo_url) {
        $config
          ->set('logo.url', $logo_url);
      }
      elseif (($logo_path = $config
        ->get('logo.path')) && file_exists($logo_path)) {
        $config
          ->set('logo.url', file_create_url($logo_path));
      }
    }

    // Generate the path to the favicon.
    if ($config
      ->get('features.favicon')) {
      $favicon_url = $theme
        ->getPath() . '/favicon.ico';
      if ($config
        ->get('favicon.use_default') && file_exists($favicon_url)) {
        $config
          ->set('favicon.url', file_create_url($favicon_url));
      }
      elseif ($favicon_path = $config
        ->get('favicon.path')) {
        $config
          ->set('favicon.url', file_create_url($favicon_path));
      }
    }

    // Retrieve the config data.
    $data = $config
      ->get();

    // Retrieve a diff of settings that override the defaults.
    $diff = DiffArray::diffAssocRecursive($data, $this->defaults);

    // Ensure core features are always present in the diff. The theme settings
    // form will not work properly otherwise.
    // @todo Just rebuild the features section of the form?
    foreach ([
      'favicon',
      'features',
      'logo',
    ] as $key) {
      $arrays = [];
      $arrays[] = isset($this->defaults[$key]) ? $this->defaults[$key] : [];
      $arrays[] = isset($data[$key]) ? $data[$key] : [];
      $diff[$key] = NestedArray::mergeDeepArray($arrays, TRUE);
    }
    return $diff;
  }

  /**
   * Determines if a setting overrides the default value.
   *
   * @param string $name
   *   The name of the setting to check.
   * @param mixed $value
   *   The new value to check.
   *
   * @return bool
   *   TRUE or FALSE
   */
  public function overridesValue($name, $value) {

    // Retrieve the currently stored value for comparison purposes.
    $current_value = $this
      ->get($name);

    // Due to the nature of DiffArray::diffAssocRecursive, if the provided
    // value is an empty array, it cannot be iterated over to determine if
    // the values are different. Instead, it must be checked explicitly.
    // @see https://www.drupal.org/node/2771121
    if ($value === [] && $current_value !== []) {
      return TRUE;
    }

    // Otherwise, determine if value is overridden by any array differences.
    return !!DiffArray::diffAssocRecursive([
      $name => $value,
    ], [
      $name => $current_value,
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function save($has_trusted_data = FALSE) {
    parent::save($has_trusted_data);
    $this->theme
      ->getCache('settings')
      ->deleteAll();
    return $this;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CacheableDependencyTrait::$cacheContexts protected property Cache contexts.
CacheableDependencyTrait::$cacheMaxAge protected property Cache max-age.
CacheableDependencyTrait::$cacheTags protected property Cache tags.
CacheableDependencyTrait::setCacheability protected function Sets cacheability; useful for value object constructors.
Config::$eventDispatcher protected property An event dispatcher instance to use for configuration events.
Config::$moduleOverrides protected property The current module overrides.
Config::$overriddenData protected property The current runtime data.
Config::$settingsOverrides protected property The current settings overrides.
Config::clear public function Unsets a value in this configuration object. Overrides ConfigBase::clear 1
Config::delete public function Deletes the configuration object. Overrides StorableConfigBase::delete 1
Config::getRawData public function Gets the raw data without overrides.
Config::hasOverrides public function Determines if overrides are applied to a key for this configuration object.
Config::initWithData public function Initializes a configuration object with pre-loaded data. Overrides StorableConfigBase::initWithData
Config::resetOverriddenData protected function Resets the current data, so overrides are re-applied.
Config::set public function Sets a value in this configuration object. Overrides ConfigBase::set 1
Config::setData public function Replaces the data of this configuration object. Overrides ConfigBase::setData
Config::setModuleOverride public function Sets module overrides for this configuration object.
Config::setOverriddenData protected function Sets the current data for this configuration object.
Config::setSettingsOverride public function Sets settings.php overrides for this configuration object.
ConfigBase::$data protected property The data of the configuration object.
ConfigBase::$name protected property The name of the configuration object.
ConfigBase::castSafeStrings protected function Casts any objects that implement MarkupInterface to string.
ConfigBase::getCacheContexts public function The cache contexts associated with this object. Overrides CacheableDependencyTrait::getCacheContexts
ConfigBase::getCacheMaxAge public function The maximum age for which this object may be cached. Overrides CacheableDependencyTrait::getCacheMaxAge
ConfigBase::getName public function Returns the name of this configuration object.
ConfigBase::MAX_NAME_LENGTH constant The maximum length of a configuration object name.
ConfigBase::merge public function Merges data into a configuration object.
ConfigBase::setName public function Sets the name of this configuration object.
ConfigBase::validateKeys protected function Validates all keys in a passed in config array structure.
ConfigBase::validateName public static function Validates the configuration object name.
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
RefinableCacheableDependencyTrait::addCacheableDependency public function 1
RefinableCacheableDependencyTrait::addCacheContexts public function
RefinableCacheableDependencyTrait::addCacheTags public function
RefinableCacheableDependencyTrait::mergeCacheMaxAge public function
StorableConfigBase::$isNew protected property Whether the configuration object is new or has been saved to the storage.
StorableConfigBase::$originalData protected property The data of the configuration object.
StorableConfigBase::$schemaWrapper protected property The config schema wrapper object for this configuration object.
StorableConfigBase::$storage protected property The storage used to load and save this configuration object.
StorableConfigBase::$typedConfigManager protected property The typed config manager.
StorableConfigBase::castValue protected function Casts the value to correct data type using the configuration schema.
StorableConfigBase::getSchemaWrapper protected function Gets the schema wrapper for the whole configuration object.
StorableConfigBase::getStorage public function Retrieves the storage used to load and save this configuration object.
StorableConfigBase::isNew public function Returns whether this configuration object is new.
StorableConfigBase::validateValue protected function Validate the values are allowed data types.
ThemeSettings::$defaults protected property The default settings.
ThemeSettings::$theme protected property The current theme object.
ThemeSettings::get public function Gets data from this configuration object. Overrides Config::get
ThemeSettings::getCacheTags public function The cache tags associated with this object. Overrides ConfigBase::getCacheTags
ThemeSettings::getOriginal public function Gets original data from this configuration object. Overrides Config::getOriginal
ThemeSettings::getThemeConfig public function Retrieves a specific theme's stored config settings.
ThemeSettings::overridesValue public function Determines if a setting overrides the default value.
ThemeSettings::save public function Saves the configuration object. Overrides Config::save
ThemeSettings::__construct public function Constructs a configuration object. Overrides Config::__construct