From 40cc21c89df9da42dc076ae9ab1e39f75fa01a66 Mon Sep 17 00:00:00 2001 From: sun <sun@unleashedmind.com> Date: Tue, 14 Feb 2012 14:39:26 +0100 Subject: [PATCH] Fixed Image module tests. Added many critical todos: - Config values are not casted to strings (despite promised). - Config keys are not casted to strings (although promised, too). - XML can be invalid and not parse-able for many reasons. - Config keys are not validated/sanitized. - config()->clear() should really be ->unset(). - Configuration must not be additionally cached by a module in any way (static cache / database cache). - Some modules invoke drupal_alter() on configuration (e.g., image styles). - Need a way to list config object names/suffixes _after_ a specified prefix. - Need a way to determine whether a config object exists. - Some modules might have a valid use-case for retrieving/listing config objects using a wildcard within the name (instead of only searching by prefix). - The key of a retrieved value is unknown; since you only get the value. Configuration values (or sub-values) may be passed forward to another function/callback, and thus, that function no longer knows about the key of the value. (unless the key is contained in the value, which is a very very wonky duplication) - Config keys must not contain periods (within a specific key). --- core/includes/config.inc | 8 +- .../Drupal/Core/Config/ConfigException.php | 2 +- core/lib/Drupal/Core/Config/DrupalConfig.php | 10 ++ core/modules/image/image.install | 81 ------------- core/modules/image/image.module | 113 +++++++++++------- core/modules/image/image.test | 2 +- 6 files changed, 86 insertions(+), 130 deletions(-) diff --git a/core/includes/config.inc b/core/includes/config.inc index 7f59ba32cbdb..e60eca897154 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -188,7 +188,7 @@ function config_xml_to_array($data) { } foreach ($xmlObject as $index => $content) { if (is_object($content)) { - $out[$index] = config_xml2array($content); + $out[$index] = config_xml_to_array($content); } } @@ -219,6 +219,8 @@ function config_encode($data) { $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $dom->loadXML($xml_object->asXML()); + // @todo The loaded XML can be invalid; throwing plenty of PHP warnings but no + // catchable error. return $dom->saveXML(); } @@ -246,7 +248,9 @@ function config_array_to_xml($array, &$xml_object) { } } else { - $xml_object->addChild("$key", "$value"); + // @todo Cast to string must happen in DrupalConfig::set() already. But + // over there, $value may also be an array, so the result is "Array". + $xml_object->addChild($key, (string) $value); } } } diff --git a/core/lib/Drupal/Core/Config/ConfigException.php b/core/lib/Drupal/Core/Config/ConfigException.php index a115c9352f95..c60a449822f8 100644 --- a/core/lib/Drupal/Core/Config/ConfigException.php +++ b/core/lib/Drupal/Core/Config/ConfigException.php @@ -5,4 +5,4 @@ /** * @todo */ -class ConfigException extends Exception {} +class ConfigException extends \Exception {} diff --git a/core/lib/Drupal/Core/Config/DrupalConfig.php b/core/lib/Drupal/Core/Config/DrupalConfig.php index 5cf2c622ead9..121fac7eb615 100644 --- a/core/lib/Drupal/Core/Config/DrupalConfig.php +++ b/core/lib/Drupal/Core/Config/DrupalConfig.php @@ -3,6 +3,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Config\DrupalConfigVerifiedStorageInterface; +use Drupal\Core\Config\ConfigException; /** * Represents the default configuration storage object. @@ -105,6 +106,13 @@ public function get($key = '') { * @todo */ public function set($key, $value) { + // Remove all non-alphanumeric characters from the key. + // @todo Reverse this and throw an exception when encountering a key with + // invalid name. The identical validation also needs to happen in get(). + // Furthermore, the dot/period is a reserved character; it may appear + // between keys, but not within keys. + $key = preg_replace('@[^a-zA-Z0-9_.-]@', '', $key); + $parts = explode('.', $key); if (count($parts) == 1) { $this->data[$key] = $value; @@ -119,6 +127,8 @@ public function set($key, $value) { * * @param $key * @todo + * + * @todo Rename into unset(). */ public function clear($key) { $parts = explode('.', $key); diff --git a/core/modules/image/image.install b/core/modules/image/image.install index 02be57ca4c5f..91349a92a292 100644 --- a/core/modules/image/image.install +++ b/core/modules/image/image.install @@ -22,87 +22,6 @@ function image_uninstall() { file_unmanaged_delete_recursive(file_default_scheme() . '://styles'); } -/** - * Implements hook_schema(). - */ -function image_schema() { - $schema = array(); - - $schema['image_styles'] = array( - 'description' => 'Stores configuration options for image styles.', - 'fields' => array( - 'isid' => array( - 'description' => 'The primary identifier for an image style.', - 'type' => 'serial', - 'unsigned' => TRUE, - 'not null' => TRUE, - ), - 'name' => array( - 'description' => 'The style name.', - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - ), - ), - 'primary key' => array('isid'), - 'unique keys' => array( - 'name' => array('name'), - ), - ); - - $schema['image_effects'] = array( - 'description' => 'Stores configuration options for image effects.', - 'fields' => array( - 'ieid' => array( - 'description' => 'The primary identifier for an image effect.', - 'type' => 'serial', - 'unsigned' => TRUE, - 'not null' => TRUE, - ), - 'isid' => array( - 'description' => 'The {image_styles}.isid for an image style.', - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - ), - 'weight' => array( - 'description' => 'The weight of the effect in the style.', - 'type' => 'int', - 'unsigned' => FALSE, - 'not null' => TRUE, - 'default' => 0, - ), - 'name' => array( - 'description' => 'The unique name of the effect to be executed.', - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - ), - 'data' => array( - 'description' => 'The configuration data for the effect.', - 'type' => 'blob', - 'not null' => TRUE, - 'size' => 'big', - 'serialize' => TRUE, - ), - ), - 'primary key' => array('ieid'), - 'indexes' => array( - 'isid' => array('isid'), - 'weight' => array('weight'), - ), - 'foreign keys' => array( - 'image_style' => array( - 'table' => 'image_styles', - 'columns' => array('isid' => 'isid'), - ), - ), - ); - - return $schema; -} - /** * Implements hook_field_schema(). */ diff --git a/core/modules/image/image.module b/core/modules/image/image.module index 09841c50aad0..851ba141b1cf 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -435,33 +435,30 @@ function image_path_flush($path) { * @see image_style_load() */ function image_styles() { - $styles = &drupal_static(__FUNCTION__); - - // Grab from cache or build the array. - if (!isset($styles)) { - if ($cache = cache()->get('image_styles')) { - $styles = $cache->data; - } - else { + // @todo Configuration must not be statically cached nor cache-system cached. + // However, there's a drupal_alter() involved here. + +// $styles = &drupal_static(__FUNCTION__); +// +// // Grab from cache or build the array. +// if (!isset($styles)) { +// if ($cache = cache()->get('image_styles')) { +// $styles = $cache->data; +// } +// else { $styles = array(); // Select the styles we have configured. - foreach (config_get_signed_file_storage_names_with_prefix('image.styles') as $config_name) { - $style = array(); - $config = config($config_name); - $style['name'] = $config->get('name'); - $style['effects'] = array(); - foreach ($config->get('effects') as $key => $effect) { - $definition = image_effect_definition_load($effect['name']); - $effect = array_merge($definition, $effect); - $style['effects'][$key] = $effect; - } + $configured_styles = config_get_verified_storage_names_with_prefix('image.styles'); + foreach ($configured_styles as $config_name) { + // @todo Allow to retrieve the name without prefix only. + $style = image_style_load(str_replace('image.styles.', '', $config_name)); $styles[$style['name']] = $style; } drupal_alter('image_styles', $styles); - cache()->set('image_styles', $styles); - } - } +// cache()->set('image_styles', $styles); +// } +// } return $styles; } @@ -478,16 +475,24 @@ function image_styles() { * If the image style name is not valid, an empty array is returned. * @see image_effect_load() */ -function image_style_load($name = NULL) { - $styles = image_styles(); +function image_style_load($name) { + $style = config('image.styles.' . $name)->get(); - // If retrieving by name. - if (isset($name) && isset($styles[$name])) { - return $styles[$name]; + // @todo Requires a more reliable + generic method to check for whether the + // configuration object exists. + if (!isset($style['name'])) { + return FALSE; } - // Otherwise the style was not found. - return FALSE; + foreach ($style['effects'] as $ieid => $effect) { + $definition = image_effect_definition_load($effect['name']); + $effect = array_merge($definition, $effect); + $style['effects'][$ieid] = $effect; + } + // Sort effects by weight. + uasort($style['effects'], 'drupal_sort_weight'); + + return $style; } /** @@ -508,6 +513,8 @@ function image_style_save($style) { $config->set('effects', array()); } $config->save(); + // @todo is_new must only be set when the configuration object did not exist + // yet. $style['is_new'] = TRUE; // Let other modules update as necessary on save. @@ -554,8 +561,7 @@ function image_style_delete($style, $replacement_style_name = '') { * format array('isid' => array()), or an empty array if the specified style * has no effects. * - * @todo I think this function can be deprecated since we automatically - * load all effects with a style now. + * @todo Remove this function; it's entirely obsolete. */ function image_style_effects($style) { return $style['effects']; @@ -754,11 +760,11 @@ function image_style_flush($style) { // Let other modules update as necessary on flush. module_invoke_all('image_style_flush', $style); - // Clear image style and effect caches. - cache()->delete('image_styles'); - cache()->deletePrefix('image_effects:'); - drupal_static_reset('image_styles'); - drupal_static_reset('image_effects'); +// // Clear image style and effect caches. +// cache()->delete('image_styles'); +// cache()->deletePrefix('image_effects:'); +// drupal_static_reset('image_styles'); +// drupal_static_reset('image_effects'); // Clear field caches so that formatters may be added for this style. field_info_cache_clear(); @@ -899,6 +905,8 @@ function image_effect_definition_load($effect) { * @return * An array of all image effects. * @see image_effect_load() + * + * @todo Remove after moving/resolving the todo. */ function image_effects() { $effects = &drupal_static(__FUNCTION__); @@ -907,6 +915,9 @@ function image_effects() { $effects = array(); // Add database image effects. + // @todo Strictly speaking, this is obsolete. However, it demonstrates a + // use-case for retrieving/listing configuration objects using a wildcard + // within the name (instead of only the suffix). $result = db_select('image_effects', NULL, array('fetch' => PDO::FETCH_ASSOC)) ->fields('image_effects') ->orderBy('image_effects.weight', 'ASC') @@ -928,13 +939,11 @@ function image_effects() { /** * Load a single image effect. * - * @param $name - * The image effect name. + * @param $ieid + * The image effect ID. * @param $style_name * The image style name. - * @param $include - * If set, this loader will restrict to a specific type of image style, may be - * one of the defined Image style storage constants. + * * @return * An image effect array, consisting of the following keys: * - "ieid": The unique image effect ID. @@ -947,9 +956,20 @@ function image_effects() { * @see image_style_load() * @see image_effect_definition_load() */ -function image_effect_load($name, $style_name) { - if (($style = image_style_load($style_name)) && isset($style['effects'][$name])) { - return $style['effects'][$name]; +function image_effect_load($ieid, $style_name) { + if (($style = image_style_load($style_name)) && isset($style['effects'][$ieid])) { + $effect = $style['effects'][$ieid]; + $definition = image_effect_definition_load($effect['name']); + $effect = array_merge($definition, $effect); + // @todo The effect's key name within the style is unknown. It *should* be + // identical to the ieid, but that is in no way guaranteed. And of course, + // the ieid key *within* the effect is senseless duplication in the first + // place. This problem can be eliminated in many places, but especially + // for loaded menu arguments like %image_effect, the actual router + // callbacks don't have access to 'ieid' anymore (unless resorting to + // dirty %index and %map tricks). + $effect['ieid'] = $ieid; + return $effect; } return FALSE; } @@ -979,15 +999,18 @@ function image_effect_save($style_name, $effect) { // The machine name is all the elements of the data array concatenated // together, delimited by underscores. $machine_name = $effect['name']; - foreach ($effect['data'] as $key => $value) { $machine_name .= '_' . $value; } + // @todo The machine name must not use any special non-alphanumeric + // characters, and may also not contain dots/periods, as that is the + // config system's nested key syntax. + $machine_name = preg_replace('@[^a-zA-Z0-9_-]@', '', $machine_name); $effect['ieid'] = $machine_name; $config->set('effects.' . $machine_name, $effect); } $config->save(); - $style = image_style_load(NULL, $style_name); + $style = image_style_load($style_name); image_style_flush($style); return $effect; } diff --git a/core/modules/image/image.test b/core/modules/image/image.test index 91b5e4faa6e3..8081bf079418 100644 --- a/core/modules/image/image.test +++ b/core/modules/image/image.test @@ -468,7 +468,7 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase { // Load the style by the new name with the new weights. drupal_static_reset('image_styles'); - $style = image_style_load($style_name, NULL); + $style = image_style_load($style_name); // Confirm the new style order was saved. $effect_edits_order = array_reverse($effect_edits_order); -- GitLab