From 4b867a063a4e659c0a447f1c0eecb3bf24fdbd23 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Thu, 11 Sep 2014 16:12:25 +0800 Subject: [PATCH] MDL-46585 lang: display debugging message when deprecated string is used --- lib/classes/string_manager.php | 11 ++++ lib/classes/string_manager_install.php | 13 +++++ lib/classes/string_manager_standard.php | 67 +++++++++++++++++++++- lib/tests/string_manager_standard_test.php | 46 +++++++++++++++ 4 files changed, 136 insertions(+), 1 deletion(-) diff --git a/lib/classes/string_manager.php b/lib/classes/string_manager.php index b0d617f146b..ce40cd1e538 100644 --- a/lib/classes/string_manager.php +++ b/lib/classes/string_manager.php @@ -61,6 +61,17 @@ interface core_string_manager { */ public function string_exists($identifier, $component); + /** + * Has string been deprecated? + * + * Usually checked only inside get_string() to display debug warnings. + * + * @param string $identifier The identifier of the string to search for + * @param string $component The module the string is associated with + * @return bool true if deprecated + */ + public function string_deprecated($identifier, $component); + /** * Returns a localised list of all country names, sorted by country keys. * @param bool $returnall return all or just enabled diff --git a/lib/classes/string_manager_install.php b/lib/classes/string_manager_install.php index 353e5072dae..d970c73d59b 100644 --- a/lib/classes/string_manager_install.php +++ b/lib/classes/string_manager_install.php @@ -79,6 +79,19 @@ class core_string_manager_install implements core_string_manager { return (strpos($str, '[[') === false); } + /** + * Has string been deprecated? + * + * No deprecated string in installation, unused strings are simply removed. + * + * @param string $identifier The identifier of the string to search for + * @param string $component The module the string is associated with + * @return bool true if deprecated + */ + public function string_deprecated($identifier, $component) { + return false; + } + /** * Get String returns a requested string * diff --git a/lib/classes/string_manager_standard.php b/lib/classes/string_manager_standard.php index 7ec3708f4a3..6482c67e28a 100644 --- a/lib/classes/string_manager_standard.php +++ b/lib/classes/string_manager_standard.php @@ -47,6 +47,8 @@ class core_string_manager_standard implements core_string_manager { protected $translist; /** @var cache stores list of available translations */ protected $menucache; + /** @var array list of cached deprecated strings */ + protected $cacheddeprecated; /** * Create new instance of string manager @@ -206,6 +208,57 @@ class core_string_manager_standard implements core_string_manager { return $string; } + /** + * Parses all deprecated.txt in all plugins lang locations and returns the list of deprecated strings. + * + * Static variable is used for caching, this function is only called in dev environment. + * + * @return array of deprecated strings in the same format they appear in deprecated.txt files: "identifier,component" + * where component is a normalised component (i.e. "core_moodle", "mod_assign", etc.) + */ + protected function load_deprecated_strings() { + global $CFG; + + if ($this->cacheddeprecated !== null) { + return $this->cacheddeprecated; + } + + $this->cacheddeprecated = array(); + $content = ''; + $filename = $CFG->dirroot . '/lang/en/deprecated.txt'; + if (file_exists($filename)) { + $content .= file_get_contents($filename); + } + foreach (core_component::get_plugin_types() as $plugintype => $plugintypedir) { + foreach (core_component::get_plugin_list($plugintype) as $pluginname => $plugindir) { + $filename = $plugindir.'/lang/en/deprecated.txt'; + if (file_exists($filename)) { + $content .= "\n". file_get_contents($filename); + } + } + } + + $strings = preg_split('/\s*\n\s*/', $content, -1, PREG_SPLIT_NO_EMPTY); + $this->cacheddeprecated = array_flip($strings); + + return $this->cacheddeprecated; + } + + /** + * Has string been deprecated? + * + * Usually checked only inside get_string() to display debug warnings. + * + * @param string $identifier The identifier of the string to search for + * @param string $component The module the string is associated with + * @return bool true if deprecated + */ + public function string_deprecated($identifier, $component) { + $deprecated = $this->load_deprecated_strings(); + list($plugintype, $pluginname) = core_component::normalize_component($component); + return isset($deprecated[$identifier . ',' . $plugintype . '_' . $pluginname]); + } + /** * Does the string actually exist? * @@ -234,6 +287,8 @@ class core_string_manager_standard implements core_string_manager { * @return string The String ! */ public function get_string($identifier, $component = '', $a = null, $lang = null) { + global $CFG; + $this->countgetstring++; // There are very many uses of these time formatting strings without the 'langconfig' component, // it would not be reasonable to expect that all of them would be converted during 2.0 migration. @@ -279,7 +334,7 @@ class core_string_manager_standard implements core_string_manager { // Devs need to learn to purge all caches after any change or disable $CFG->langstringcache. if (!isset($string[$identifier])) { // The string is still missing - should be fixed by developer. - if (debugging('', DEBUG_DEVELOPER)) { + if ($CFG->debugdeveloper) { list($plugintype, $pluginname) = core_component::normalize_component($component); if ($plugintype === 'core') { $file = "lang/en/{$component}.php"; @@ -324,6 +379,16 @@ class core_string_manager_standard implements core_string_manager { } } + if ($CFG->debugdeveloper) { + // Display a debugging message if sting exists but was deprecated. + if ($this->string_deprecated($identifier, $component)) { + list($plugintype, $pluginname) = core_component::normalize_component($component); + debugging("String [{$identifier},{$plugintype}_{$pluginname}] is deprecated. ". + 'Either you should no longer be using that string, or the string has been incorrectly deprecated, in which case you should report this as a bug. '. + 'Please refer to https://docs.moodle.org/dev/String_deprecation', DEBUG_DEVELOPER); + } + } + return $string; } diff --git a/lib/tests/string_manager_standard_test.php b/lib/tests/string_manager_standard_test.php index 6ae3bbe9d37..1507b88175b 100644 --- a/lib/tests/string_manager_standard_test.php +++ b/lib/tests/string_manager_standard_test.php @@ -67,6 +67,48 @@ class core_string_manager_standard_testcase extends advanced_testcase { // Descendant of an orphaned language (N/A < bb < bc). $this->assertSame(array('bb', 'bc'), $stringman->get_language_dependencies('bc')); } + + public function test_deprecated_strings() { + $stringman = get_string_manager(); + + // Check non-deprecated string. + $this->assertFalse($stringman->string_deprecated('hidden', 'grades')); + + // Check deprecated string. + $this->assertTrue($stringman->string_deprecated('hidden', 'repository')); + $this->assertTrue($stringman->string_exists('hidden', 'repository')); + $this->assertDebuggingNotCalled(); + $this->assertEquals('Hidden', get_string('hidden', 'repository')); + $this->assertDebuggingCalled('String [hidden,core_repository] is deprecated. '. + 'Either you should no longer be using that string, or the string has been incorrectly deprecated, in which case you should report this as a bug. '. + 'Please refer to https://docs.moodle.org/dev/String_deprecation'); + } + + /** + * This test is a built-in validation of deprecated.txt files in lang locations. + * + * It will fail if the string in the wrong format or non-existing (mistyped) string was deprecated. + */ + public function test_validate_deprecated_strings_files() { + global $CFG; + $stringman = get_string_manager(); + $teststringman = testable_core_string_manager::instance($CFG->langotherroot, $CFG->langlocalroot, array()); + $allstrings = $teststringman->get_all_deprecated_strings(); + + foreach ($allstrings as $string) { + if (!preg_match('/^(.*),(.*)$/', $string, $matches) || + clean_param($matches[2], PARAM_COMPONENT) !== $matches[2]) { + $this->fail('String "'.$string.'" appearing in one of the lang/en/deprecated.txt files does not have correct syntax'); + } + list($pluginttype, $pluginname) = core_component::normalize_component($matches[2]); + if ($matches[2] !== $pluginttype . '_' . $pluginname) { + $this->fail('String "'.$string.'" appearing in one of the lang/en/deprecated.txt files does not have normalised component name'); + } + if (!$stringman->string_exists($matches[1], $matches[2])) { + $this->fail('String "'.$string.'" appearing in one of the lang/en/deprecated.txt files does not exist'); + } + } + } } @@ -101,4 +143,8 @@ class testable_core_string_manager extends core_string_manager_standard { return new testable_core_string_manager($otherroot, $localroot, $usecache, $translist, $menucache); } + + public function get_all_deprecated_strings() { + return array_flip($this->load_deprecated_strings()); + } } -- 2.43.0