diff --git a/core/includes/config.inc b/core/includes/config.inc index 8d0eea1..a9e5c8e 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -2,6 +2,7 @@ use Drupal\Core\Config\DatabaseStorage; use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\FileStorageReadException; /** * @file @@ -86,3 +87,203 @@ function config_get_storage_names_with_prefix($prefix = '') { function config($name, $class = 'Drupal\Core\Config\DrupalConfig') { return new $class(new DatabaseStorage($name)); } + +/** + * Retrieves metadata for a configuration object or key. + * + * The configuration name may contain the placeholder '*' which means generic configuration + * for all objects of this type. If it doesn't contain it, we load first the generic metadata + * and add specific configuration for this type on top of it. + * + * Example: For image.style.large + * 1. Load metadata for image.style.* + * 2. Merge metadata for image.style.large + * + * @param $name + * Configuration name. + * @param $key + * Configuration key. + */ +function config_meta_data($name, $key = '') { + $meta = &drupal_static(__FUNCTION__); + if (!isset($meta[$name])) { + $meta[$name] = array(); + // Get first part of name that will determine the module that owns this configuration. + $parts = explode('.', $name); + $module = $parts[0]; + // We are looking for a file in $module/meta/$name.yml + $module_meta_dir = drupal_get_path('module', $module) . '/meta'; + if (is_dir($module_meta_dir)) { + // If the name doesn't contain '*', start with the generic data + $last = array_pop($parts); + if ($last != '*') { + // Try name ended in * if this one does not exist. + $base_name = implode('.', array_merge($parts, array('*'))); + $meta[$name] = config_meta_data($base_name); + } + try { + $storage = new Filestorage($name); + $storage->setPath($module_meta_dir); + $meta[$name] = drupal_array_merge_deep($meta[$name], $storage->read()); + } + catch (Drupal\Core\Config\FileStorageReadException $e) { + // Either the file does not exist or we cannot decode it. + // Do nothing. In the worst case, the value will be an empty array. + } + } + } + if ($key) { + return isset($meta[$name][$key]) ? $meta[$name][$key] : array(); + } + else { + return $meta[$name]; + } +} + +/** + * Build nested configuration properties. + */ +function config_meta_build($name, $data) { + $meta = config_meta_data($name); + $build = _config_meta_match($meta, $data); + return $build; +} + +/** + * Match configuration metadata against real configuration data. + */ +function _config_meta_match($meta, $data, $name = '', $prefix = '', $group = '') { + $build = array(); + foreach ($data as $key => $value) { + $index = _config_meta_name($prefix, $key); + if (!isset($meta[$index])) { + // Default element type when we have no metadata. + $build += _config_meta_element(array('type' => 'value'), $value, $name, $key, $group); + } + elseif (!empty($meta[$index]['subkeys'])) { + // First build the base element, then build each element + $build += _config_meta_element($meta[$index], NULL, $name, $key, $group); + // Nested elements, find subkeys in the file, the current key will be the prefix. + $group_name = _config_meta_name($name, $key); + $build += _config_meta_match($meta, $value, $group_name, $key, $group_name); + } + else { + $build += _config_meta_element($meta[$index], $value, $name, $key, $group); + } + } + return $build; +} + +/** + * Build configuration element with data and metadata. + * + * @param $base + * Base name for this element. + * @param $index + * Index of this element in the data array. + */ +function _config_meta_element($meta, $data, $base, $index, $group = '') { + $build = array(); + $name = _config_meta_name($base, $index); + if (!empty($meta['nested'])) { + $build[$name] = $meta; + // Nested elements, fetch metadata for each element using two elements. + // - $meta['meta'] will contain the base metadata name. + // - $meta['nested'] will contain the property to add to the base metadata name. + foreach ($data as $key => $value) { + if (isset($value[$meta['nested']])) { + $meta_name = $value[$meta['nested']]; + } + else { + $meta_name = $meta['meta']; + } + $element_meta = config_meta_data($meta_name); + $build += _config_meta_match($element_meta, $value, _config_meta_name($name, $key), NULL, _config_meta_name($group, $name)); + } + } + else { + // End element, set data as value. + if ($group) { + $meta += array('group' => $group); + } + if (isset($data)) { + $meta += array('value' => $data); + } + $build[$name] = $meta; + } + //debug($build, "meta match name=$name index=$index"); + return $build; +} + +/** + * Helper function to build metadata name. + */ +function _config_meta_name() { + $args = func_get_args(); + return implode('.', array_filter($args)); +} + +/** + * Build configuration form with metadata and values. + */ +function config_form($form, &$form_state, $name) { + $data = config($name)->get(); + $build = config_meta_build($name, $data); + // Keep a mapping from config name to array element for nested elements. + $mapping = array(); + foreach ($build as $name => $meta) { + if (!empty($meta['type'])) { + if (!empty($meta['group'])) { + $group = $meta['group']; + $mapping[$group][$name] = _config_form_element($meta); + $mapping[$name] = &$mapping[$group][$name]; + } + else { + $form[$name] = _config_form_element($meta); + $mapping[$name] = &$form[$name]; + } + } + } + return $form; +} + +/** + * Create configuration form element. + */ +function _config_form_element($meta) { + $element = array(); + foreach ($meta as $key => $value) { + switch ($key) { + case 'nested': + case 'meta': + case 'subkeys': + case 'group': + // Do nothing, these are config only properties. + break; + case 'value': + // Where we set the value will depend on the type of element. + switch ($meta['type']) { + case 'value': + $element['#value'] = $value; + break; + case 'item': + $element['#markup'] = $value; + break; + default: + $element['#default_value'] = $value; + } + + break; + case 'title': + case 'description': + // Translatable values. + $element['#' . $key] = t($value); + break; + default: + // Other properties just move to form notation. + $element['#' . $key] = $value; + break; + } + } + return $element; +} diff --git a/core/modules/image/config/image.style.large.yml b/core/modules/image/config/image.style.large.yml index e4f2e1f..df8daa8 100644 --- a/core/modules/image/config/image.style.large.yml +++ b/core/modules/image/config/image.style.large.yml @@ -1,7 +1,7 @@ name: large effects: image_scale_480_480_1: - name: image_scale + name: image.style.effects.scale data: width: '480' height: '480' diff --git a/core/modules/image/config/image.style.medium.yml b/core/modules/image/config/image.style.medium.yml index 17196b4..b26c71f 100644 --- a/core/modules/image/config/image.style.medium.yml +++ b/core/modules/image/config/image.style.medium.yml @@ -1,7 +1,7 @@ name: medium effects: image_scale_220_220_1: - name: image_scale + name: image.style.effects.scale data: width: '220' height: '220' diff --git a/core/modules/image/config/image.style.thumbnail.yml b/core/modules/image/config/image.style.thumbnail.yml index 2e6b9c4..c44308d 100644 --- a/core/modules/image/config/image.style.thumbnail.yml +++ b/core/modules/image/config/image.style.thumbnail.yml @@ -1,7 +1,7 @@ name: thumbnail effects: image_scale_100_100_1: - name: image_scale + name: image.style.effects.scale data: width: '100' height: '100' diff --git a/core/modules/image/image.effects.inc b/core/modules/image/image.effects.inc index 35a6a74..d491796 100644 --- a/core/modules/image/image.effects.inc +++ b/core/modules/image/image.effects.inc @@ -10,7 +10,7 @@ */ function image_image_effect_info() { $effects = array( - 'image_resize' => array( + 'image.style.effects.resize' => array( 'label' => t('Resize'), 'help' => t('Resizing will make images an exact set of dimensions. This may cause images to be stretched or shrunk disproportionately.'), 'effect callback' => 'image_resize_effect', @@ -18,7 +18,7 @@ function image_image_effect_info() { 'form callback' => 'image_resize_form', 'summary theme' => 'image_resize_summary', ), - 'image_scale' => array( + 'image.style.effects.scale' => array( 'label' => t('Scale'), 'help' => t('Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.'), 'effect callback' => 'image_scale_effect', @@ -26,7 +26,7 @@ function image_image_effect_info() { 'form callback' => 'image_scale_form', 'summary theme' => 'image_scale_summary', ), - 'image_scale_and_crop' => array( + 'image.style.effects.scale_and_crop' => array( 'label' => t('Scale and crop'), 'help' => t('Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.'), 'effect callback' => 'image_scale_and_crop_effect', @@ -34,7 +34,7 @@ function image_image_effect_info() { 'form callback' => 'image_resize_form', 'summary theme' => 'image_resize_summary', ), - 'image_crop' => array( + 'image.style.effects.crop' => array( 'label' => t('Crop'), 'help' => t('Cropping will remove portions of an image to make it the specified dimensions.'), 'effect callback' => 'image_crop_effect', @@ -42,13 +42,13 @@ function image_image_effect_info() { 'form callback' => 'image_crop_form', 'summary theme' => 'image_crop_summary', ), - 'image_desaturate' => array( + 'image.style.effects.desaturate' => array( 'label' => t('Desaturate'), 'help' => t('Desaturate converts an image to grayscale.'), 'effect callback' => 'image_desaturate_effect', 'dimensions passthrough' => TRUE, ), - 'image_rotate' => array( + 'image.style.effects.rotate' => array( 'label' => t('Rotate'), 'help' => t('Rotating an image may cause the dimensions of an image to increase to fit the diagonal.'), 'effect callback' => 'image_rotate_effect', diff --git a/core/modules/image/meta/image.style.*.yml b/core/modules/image/meta/image.style.*.yml new file mode 100644 index 0000000..627fe5b --- /dev/null +++ b/core/modules/image/meta/image.style.*.yml @@ -0,0 +1,8 @@ +name: + title: 'Machine name' + type: 'machine_name' +effects: + title: 'Style effects' + type: 'fieldset' + nested: 'name' + meta: 'image.style.effects.*' diff --git a/core/modules/image/meta/image.style.effects.*.yml b/core/modules/image/meta/image.style.effects.*.yml new file mode 100644 index 0000000..672db16 --- /dev/null +++ b/core/modules/image/meta/image.style.effects.*.yml @@ -0,0 +1,13 @@ +name: + title: 'Style name' + type: 'item' +data: + title: 'Data' + type: 'fieldset' + subkeys: '1' +weight: + title: 'Weight' + type: 'weight' +ieid: + title: 'IEID' + type: 'ieid' diff --git a/core/modules/image/meta/image.style.effects.scale.yml b/core/modules/image/meta/image.style.effects.scale.yml new file mode 100644 index 0000000..f634bc6 --- /dev/null +++ b/core/modules/image/meta/image.style.effects.scale.yml @@ -0,0 +1,9 @@ +data.width: + title: 'Width' + type: 'number' +data.height: + title: 'Height' + type: 'number' +data.upscale: + title: 'Upscale' + type: 'checkbox' diff --git a/core/modules/system/meta/system.cron.yml b/core/modules/system/meta/system.cron.yml new file mode 100644 index 0000000..5e3250e --- /dev/null +++ b/core/modules/system/meta/system.cron.yml @@ -0,0 +1,7 @@ +cron_max_threshold: + title: 'Cron max threshold' + type: 'integer' +cron_safe_threshold: + title: 'Cron safe threshold' + type: 'integer' + diff --git a/core/modules/system/meta/system.performance.yml b/core/modules/system/meta/system.performance.yml new file mode 100644 index 0000000..475041f --- /dev/null +++ b/core/modules/system/meta/system.performance.yml @@ -0,0 +1,15 @@ +cache: + title: 'Cache' + type: 'boolean' +page_cache_maximum_age: + title: 'Page cache maximum age' + type: 'time_interval' +page_compression: + title: 'Page compression' + type: 'boolean' +preprocess_css: + title: 'Preprocess CSS' + type: 'boolean' +preprocess_js: + title: 'Preprocess Javascript' + type: 'boolean'