annotate core/lib/Drupal/Core/Config/ConfigBase.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Core\Config;
Chris@0 4
Chris@0 5 use Drupal\Component\Utility\NestedArray;
Chris@0 6 use Drupal\Component\Render\MarkupInterface;
Chris@0 7 use Drupal\Core\Cache\Cache;
Chris@0 8 use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
Chris@0 9 use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
Chris@0 10 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
Chris@0 11
Chris@0 12 /**
Chris@0 13 * Provides a base class for configuration objects with get/set support.
Chris@0 14 *
Chris@0 15 * Encapsulates all capabilities needed for runtime configuration handling for
Chris@0 16 * a specific configuration object.
Chris@0 17 *
Chris@0 18 * Extend directly from this class for non-storable configuration where the
Chris@0 19 * configuration API is desired but storage is not possible; for example, if
Chris@0 20 * the data is derived at runtime. For storable configuration, extend
Chris@0 21 * \Drupal\Core\Config\StorableConfigBase.
Chris@0 22 *
Chris@0 23 * @see \Drupal\Core\Config\StorableConfigBase
Chris@0 24 * @see \Drupal\Core\Config\Config
Chris@0 25 * @see \Drupal\Core\Theme\ThemeSettings
Chris@0 26 */
Chris@0 27 abstract class ConfigBase implements RefinableCacheableDependencyInterface {
Chris@0 28 use DependencySerializationTrait;
Chris@0 29 use RefinableCacheableDependencyTrait;
Chris@0 30
Chris@0 31 /**
Chris@0 32 * The name of the configuration object.
Chris@0 33 *
Chris@0 34 * @var string
Chris@0 35 */
Chris@0 36 protected $name;
Chris@0 37
Chris@0 38 /**
Chris@0 39 * The data of the configuration object.
Chris@0 40 *
Chris@0 41 * @var array
Chris@0 42 */
Chris@0 43 protected $data = [];
Chris@0 44
Chris@0 45 /**
Chris@0 46 * The maximum length of a configuration object name.
Chris@0 47 *
Chris@0 48 * Many filesystems (including HFS, NTFS, and ext4) have a maximum file name
Chris@0 49 * length of 255 characters. To ensure that no configuration objects
Chris@0 50 * incompatible with this limitation are created, we enforce a maximum name
Chris@0 51 * length of 250 characters (leaving 5 characters for the file extension).
Chris@0 52 *
Chris@0 53 * @see http://wikipedia.org/wiki/Comparison_of_file_systems
Chris@0 54 *
Chris@0 55 * Configuration objects not stored on the filesystem should still be
Chris@0 56 * restricted in name length so name can be used as a cache key.
Chris@0 57 */
Chris@0 58 const MAX_NAME_LENGTH = 250;
Chris@0 59
Chris@0 60 /**
Chris@0 61 * Returns the name of this configuration object.
Chris@0 62 *
Chris@0 63 * @return string
Chris@0 64 * The name of the configuration object.
Chris@0 65 */
Chris@0 66 public function getName() {
Chris@0 67 return $this->name;
Chris@0 68 }
Chris@0 69
Chris@0 70 /**
Chris@0 71 * Sets the name of this configuration object.
Chris@0 72 *
Chris@0 73 * @param string $name
Chris@0 74 * The name of the configuration object.
Chris@0 75 *
Chris@0 76 * @return $this
Chris@0 77 * The configuration object.
Chris@0 78 */
Chris@0 79 public function setName($name) {
Chris@0 80 $this->name = $name;
Chris@0 81 return $this;
Chris@0 82 }
Chris@0 83
Chris@0 84 /**
Chris@0 85 * Validates the configuration object name.
Chris@0 86 *
Chris@0 87 * @param string $name
Chris@0 88 * The name of the configuration object.
Chris@0 89 *
Chris@0 90 * @throws \Drupal\Core\Config\ConfigNameException
Chris@0 91 *
Chris@0 92 * @see Config::MAX_NAME_LENGTH
Chris@0 93 */
Chris@0 94 public static function validateName($name) {
Chris@0 95 // The name must be namespaced by owner.
Chris@0 96 if (strpos($name, '.') === FALSE) {
Chris@0 97 throw new ConfigNameException("Missing namespace in Config object name $name.");
Chris@0 98 }
Chris@0 99 // The name must be shorter than Config::MAX_NAME_LENGTH characters.
Chris@0 100 if (strlen($name) > self::MAX_NAME_LENGTH) {
Chris@0 101 throw new ConfigNameException("Config object name $name exceeds maximum allowed length of " . static::MAX_NAME_LENGTH . " characters.");
Chris@0 102 }
Chris@0 103
Chris@0 104 // The name must not contain any of the following characters:
Chris@0 105 // : ? * < > " ' / \
Chris@0 106 if (preg_match('/[:?*<>"\'\/\\\\]/', $name)) {
Chris@0 107 throw new ConfigNameException("Invalid character in Config object name $name.");
Chris@0 108 }
Chris@0 109 }
Chris@0 110
Chris@0 111 /**
Chris@0 112 * Gets data from this configuration object.
Chris@0 113 *
Chris@0 114 * @param string $key
Chris@0 115 * A string that maps to a key within the configuration data.
Chris@0 116 * For instance in the following configuration array:
Chris@0 117 * @code
Chris@0 118 * array(
Chris@0 119 * 'foo' => array(
Chris@0 120 * 'bar' => 'baz',
Chris@0 121 * ),
Chris@0 122 * );
Chris@0 123 * @endcode
Chris@0 124 * A key of 'foo.bar' would return the string 'baz'. However, a key of 'foo'
Chris@0 125 * would return array('bar' => 'baz').
Chris@0 126 * If no key is specified, then the entire data array is returned.
Chris@0 127 *
Chris@0 128 * @return mixed
Chris@0 129 * The data that was requested.
Chris@0 130 */
Chris@0 131 public function get($key = '') {
Chris@0 132 if (empty($key)) {
Chris@0 133 return $this->data;
Chris@0 134 }
Chris@0 135 else {
Chris@0 136 $parts = explode('.', $key);
Chris@0 137 if (count($parts) == 1) {
Chris@0 138 return isset($this->data[$key]) ? $this->data[$key] : NULL;
Chris@0 139 }
Chris@0 140 else {
Chris@0 141 $value = NestedArray::getValue($this->data, $parts, $key_exists);
Chris@0 142 return $key_exists ? $value : NULL;
Chris@0 143 }
Chris@0 144 }
Chris@0 145 }
Chris@0 146
Chris@0 147 /**
Chris@0 148 * Replaces the data of this configuration object.
Chris@0 149 *
Chris@0 150 * @param array $data
Chris@0 151 * The new configuration data.
Chris@0 152 *
Chris@0 153 * @return $this
Chris@0 154 * The configuration object.
Chris@0 155 *
Chris@0 156 * @throws \Drupal\Core\Config\ConfigValueException
Chris@0 157 * If any key in $data in any depth contains a dot.
Chris@0 158 */
Chris@0 159 public function setData(array $data) {
Chris@0 160 $data = $this->castSafeStrings($data);
Chris@0 161 $this->validateKeys($data);
Chris@0 162 $this->data = $data;
Chris@0 163 return $this;
Chris@0 164 }
Chris@0 165
Chris@0 166 /**
Chris@0 167 * Sets a value in this configuration object.
Chris@0 168 *
Chris@0 169 * @param string $key
Chris@0 170 * Identifier to store value in configuration.
Chris@0 171 * @param mixed $value
Chris@0 172 * Value to associate with identifier.
Chris@0 173 *
Chris@0 174 * @return $this
Chris@0 175 * The configuration object.
Chris@0 176 *
Chris@0 177 * @throws \Drupal\Core\Config\ConfigValueException
Chris@0 178 * If $value is an array and any of its keys in any depth contains a dot.
Chris@0 179 */
Chris@0 180 public function set($key, $value) {
Chris@0 181 $value = $this->castSafeStrings($value);
Chris@0 182 // The dot/period is a reserved character; it may appear between keys, but
Chris@0 183 // not within keys.
Chris@0 184 if (is_array($value)) {
Chris@0 185 $this->validateKeys($value);
Chris@0 186 }
Chris@0 187 $parts = explode('.', $key);
Chris@0 188 if (count($parts) == 1) {
Chris@0 189 $this->data[$key] = $value;
Chris@0 190 }
Chris@0 191 else {
Chris@0 192 NestedArray::setValue($this->data, $parts, $value);
Chris@0 193 }
Chris@0 194 return $this;
Chris@0 195 }
Chris@0 196
Chris@0 197 /**
Chris@0 198 * Validates all keys in a passed in config array structure.
Chris@0 199 *
Chris@0 200 * @param array $data
Chris@0 201 * Configuration array structure.
Chris@0 202 *
Chris@0 203 * @return null
Chris@0 204 *
Chris@0 205 * @throws \Drupal\Core\Config\ConfigValueException
Chris@0 206 * If any key in $data in any depth contains a dot.
Chris@0 207 */
Chris@0 208 protected function validateKeys(array $data) {
Chris@0 209 foreach ($data as $key => $value) {
Chris@0 210 if (strpos($key, '.') !== FALSE) {
Chris@0 211 throw new ConfigValueException("$key key contains a dot which is not supported.");
Chris@0 212 }
Chris@0 213 if (is_array($value)) {
Chris@0 214 $this->validateKeys($value);
Chris@0 215 }
Chris@0 216 }
Chris@0 217 }
Chris@0 218
Chris@0 219 /**
Chris@0 220 * Unsets a value in this configuration object.
Chris@0 221 *
Chris@0 222 * @param string $key
Chris@0 223 * Name of the key whose value should be unset.
Chris@0 224 *
Chris@0 225 * @return $this
Chris@0 226 * The configuration object.
Chris@0 227 */
Chris@0 228 public function clear($key) {
Chris@0 229 $parts = explode('.', $key);
Chris@0 230 if (count($parts) == 1) {
Chris@0 231 unset($this->data[$key]);
Chris@0 232 }
Chris@0 233 else {
Chris@0 234 NestedArray::unsetValue($this->data, $parts);
Chris@0 235 }
Chris@0 236 return $this;
Chris@0 237 }
Chris@0 238
Chris@0 239 /**
Chris@0 240 * Merges data into a configuration object.
Chris@0 241 *
Chris@0 242 * @param array $data_to_merge
Chris@0 243 * An array containing data to merge.
Chris@0 244 *
Chris@0 245 * @return $this
Chris@0 246 * The configuration object.
Chris@0 247 */
Chris@0 248 public function merge(array $data_to_merge) {
Chris@0 249 // Preserve integer keys so that configuration keys are not changed.
Chris@0 250 $this->setData(NestedArray::mergeDeepArray([$this->data, $data_to_merge], TRUE));
Chris@0 251 return $this;
Chris@0 252 }
Chris@0 253
Chris@0 254 /**
Chris@0 255 * {@inheritdoc}
Chris@0 256 */
Chris@0 257 public function getCacheContexts() {
Chris@0 258 return $this->cacheContexts;
Chris@0 259 }
Chris@0 260
Chris@0 261 /**
Chris@0 262 * {@inheritdoc}
Chris@0 263 */
Chris@0 264 public function getCacheTags() {
Chris@0 265 return Cache::mergeTags(['config:' . $this->name], $this->cacheTags);
Chris@0 266 }
Chris@0 267
Chris@0 268 /**
Chris@0 269 * {@inheritdoc}
Chris@0 270 */
Chris@0 271 public function getCacheMaxAge() {
Chris@0 272 return $this->cacheMaxAge;
Chris@0 273 }
Chris@0 274
Chris@0 275 /**
Chris@0 276 * Casts any objects that implement MarkupInterface to string.
Chris@0 277 *
Chris@0 278 * @param mixed $data
Chris@0 279 * The configuration data.
Chris@0 280 *
Chris@0 281 * @return mixed
Chris@0 282 * The data with any safe strings cast to string.
Chris@0 283 */
Chris@0 284 protected function castSafeStrings($data) {
Chris@0 285 if ($data instanceof MarkupInterface) {
Chris@0 286 $data = (string) $data;
Chris@0 287 }
Chris@0 288 elseif (is_array($data)) {
Chris@0 289 array_walk_recursive($data, function (&$value) {
Chris@0 290 if ($value instanceof MarkupInterface) {
Chris@0 291 $value = (string) $value;
Chris@0 292 }
Chris@0 293 });
Chris@0 294 }
Chris@0 295 return $data;
Chris@0 296 }
Chris@0 297
Chris@0 298 }