MDL-46585 lang: display debugging message when deprecated string is used
authorMarina Glancy <marina@moodle.com>
Thu, 11 Sep 2014 08:12:25 +0000 (16:12 +0800)
committerMarina Glancy <marina@moodle.com>
Fri, 12 Sep 2014 02:24:43 +0000 (10:24 +0800)
lib/classes/string_manager.php
lib/classes/string_manager_install.php
lib/classes/string_manager_standard.php
lib/tests/string_manager_standard_test.php

index b0d617f..ce40cd1 100644 (file)
@@ -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
index 353e507..d970c73 100644 (file)
@@ -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
      *
index 7ec3708..6482c67 100644 (file)
@@ -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;
     }
 
index 6ae3bbe..1507b88 100644 (file)
@@ -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());
+    }
 }