Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core;
18
 
19
use core\exception\coding_exception;
20
use stdClass;
21
 
22
/**
23
 * The lang_string class
24
 *
25
 * This special class is used to create an object representation of a string request.
26
 * It is special because processing doesn't occur until the object is first used.
27
 * The class was created especially to aid performance in areas where strings were
28
 * required to be generated but were not necessarily used.
29
 * As an example the admin tree when generated uses over 1500 strings, of which
30
 * normally only 1/3 are ever actually printed at any time.
31
 * The performance advantage is achieved by not actually processing strings that
32
 * aren't being used, as such reducing the processing required for the page.
33
 *
34
 * How to use the lang_string class?
35
 *     There are two methods of using the lang_string class, first through the
36
 *     forth argument of the get_string function, and secondly directly.
37
 *     The following are examples of both.
38
 * 1. Through get_string calls e.g.
39
 *     $string = get_string($identifier, $component, $a, true);
40
 *     $string = get_string('yes', 'moodle', null, true);
41
 * 2. Direct instantiation
42
 *     $string = new lang_string($identifier, $component, $a, $lang);
43
 *     $string = new lang_string('yes');
44
 *
45
 * How do I use a lang_string object?
46
 *     The lang_string object makes use of a magic __toString method so that you
47
 *     are able to use the object exactly as you would use a string in most cases.
48
 *     This means you are able to collect it into a variable and then directly
49
 *     echo it, or concatenate it into another string, or similar.
50
 *     The other thing you can do is manually get the string by calling the
51
 *     lang_strings out method e.g.
52
 *         $string = new lang_string('yes');
53
 *         $string->out();
54
 *     Also worth noting is that the out method can take one argument, $lang which
55
 *     allows the developer to change the language on the fly.
56
 *
57
 * When should I use a lang_string object?
58
 *     The lang_string object is designed to be used in any situation where a
59
 *     string may not be needed, but needs to be generated.
60
 *     The admin tree is a good example of where lang_string objects should be
61
 *     used.
62
 *     A more practical example would be any class that requires strings that may
63
 *     not be printed (after all classes get rendered by renderers and who knows
64
 *     what they will do ;))
65
 *
66
 * When should I not use a lang_string object?
67
 *     Don't use lang_strings when you are going to use a string immediately.
68
 *     There is no need as it will be processed immediately and there will be no
69
 *     advantage, and in fact perhaps a negative hit as a class has to be
70
 *     instantiated for a lang_string object, however get_string won't require
71
 *     that.
72
 *
73
 * Limitations:
74
 * 1. You cannot use a lang_string object as an array offset. Doing so will
75
 *     result in PHP throwing an error. (You can use it as an object property!)
76
 *
77
 * @package     core
78
 * @copyright   2011 Sam Hemelryk
79
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
80
 */
81
class lang_string {
82
 
83
    /** @var string The strings component. Default '' */
84
    protected ?string $component = '';
85
 
86
    /** @var array|stdClass Any arguments required for the string. Default null */
87
    protected mixed $a = null;
88
 
89
    /** @var string The processed string (once processed) */
90
    protected ?string $string = null;
91
 
92
    /**
93
     * A special boolean. If set to true then the object has been woken up and
94
     * cannot be regenerated. If this is set then $this->string MUST be used.
95
     * @var bool
96
     */
97
    protected bool $forcedstring = false;
98
 
99
    /**
100
     * Constructs a lang_string object
101
     *
102
     * This function should do as little processing as possible to ensure the best
103
     * performance for strings that won't be used.
104
     *
105
     * @param string $identifier The strings identifier
106
     * @param string|null $component The strings component
107
     * @param mixed $a Any arguments the string requires
108
     * @param string|null $lang The language to use when processing the string.
109
     * @throws coding_exception
110
     */
111
    public function __construct(
112
        /** @var string The strings identifier */
113
        protected readonly string $identifier,
114
        ?string $component = '',
115
        mixed $a = null,
116
        /** @var string The language to use when processing the string*/
117
        protected readonly ?string $lang = null,
118
    ) {
119
        if (empty($component)) {
120
            $component = 'moodle';
121
        }
122
 
123
        $this->component = $component;
124
 
125
        // We MUST duplicate $a to ensure that it if it changes by reference those
126
        // changes are not carried across.
127
        // To do this we always ensure $a or its properties/values are strings
128
        // and that any properties/values that arn't convertable are forgotten.
129
        if ($a !== null) {
130
            if (is_scalar($a)) {
131
                $this->a = $a;
132
            } else if ($a instanceof lang_string) {
133
                $this->a = $a->out();
134
            } else if (is_object($a) || is_array($a)) {
135
                $a = (array)$a;
136
                $this->a = [];
137
                foreach ($a as $key => $value) {
138
                    // Make sure conversion errors don't get displayed (results in '').
139
                    if (is_array($value)) {
140
                        $this->a[$key] = '';
141
                    } else if (is_object($value)) {
142
                        if (method_exists($value, '__toString')) {
143
                            $this->a[$key] = $value->__toString();
144
                        } else {
145
                            $this->a[$key] = '';
146
                        }
147
                    } else {
148
                        $this->a[$key] = (string)$value;
149
                    }
150
                }
151
            }
152
        }
153
 
154
        if (debugging(false, DEBUG_DEVELOPER)) {
155
            if (clean_param($this->identifier, PARAM_STRINGID) == '') {
156
                throw new coding_exception('Invalid string identifier. Most probably some illegal character is part of ' .
157
                    'the string identifier. Please check your string definition');
158
            }
159
            if (!empty($this->component) && clean_param($this->component, PARAM_COMPONENT) == '') {
160
                throw new coding_exception('Invalid string compontent. Please check your string definition');
161
            }
162
            if (!get_string_manager()->string_exists($this->identifier, $this->component)) {
163
                debugging('String does not exist. Please check your string definition for '.$this->identifier.'/'.$this->component,
164
                    DEBUG_DEVELOPER);
165
            }
166
        }
167
    }
168
 
169
    /**
170
     * Processes the string.
171
     *
172
     * This function actually processes the string, stores it in the string property
173
     * and then returns it.
174
     * You will notice that this function is VERY similar to the get_string method.
175
     * That is because it is pretty much doing the same thing.
176
     * However as this function is an upgrade it isn't as tolerant to backwards
177
     * compatibility.
178
     *
179
     * @return string
180
     * @throws coding_exception
181
     */
182
    protected function get_string(): string {
183
        global $CFG;
184
 
185
        // Check if we need to process the string.
186
        if ($this->string === null) {
187
            // Check the quality of the identifier.
188
            if ($CFG->debugdeveloper && clean_param($this->identifier, PARAM_STRINGID) === '') {
189
                throw new coding_exception('Invalid string identifier. Most probably some illegal character is part of ' .
190
                    'the string identifier. Please check your string definition', DEBUG_DEVELOPER);
191
            }
192
 
193
            // Process the string.
194
            $this->string = get_string_manager()->get_string($this->identifier, $this->component, $this->a, $this->lang);
195
            // Debugging feature lets you display string identifier and component.
196
            if (isset($CFG->debugstringids) && $CFG->debugstringids && optional_param('strings', 0, PARAM_INT)) {
197
                $this->string .= ' {' . $this->identifier . '/' . $this->component . '}';
198
            }
199
        }
200
        // Return the string.
201
        return $this->string;
202
    }
203
 
204
    /**
205
     * Returns the string
206
     *
207
     * @param string $lang The langauge to use when processing the string
208
     * @return string
209
     */
210
    public function out($lang = null): string {
211
        if ($lang !== null && $lang != $this->lang && ($this->lang == null && $lang != current_language())) {
212
            if ($this->forcedstring) {
213
                debugging('lang_string objects that have been used cannot be printed in another language. ('.$this->lang.' used)',
214
                    DEBUG_DEVELOPER);
215
                return $this->get_string();
216
            }
217
            $translatedstring = new lang_string($this->identifier, $this->component, $this->a, $lang);
218
            return $translatedstring->out();
219
        }
220
        return $this->get_string();
221
    }
222
 
223
    /**
224
     * Magic __toString method for printing a string
225
     *
226
     * @return string
227
     */
228
    public function __toString() {
229
        return $this->get_string();
230
    }
231
 
232
    /**
233
     * Magic __set_state method used for var_export
234
     *
235
     * @param array $array
236
     * @return self
237
     */
238
    public static function __set_state(array $array): self {
239
        $tmp = new lang_string($array['identifier'], $array['component'], $array['a'], $array['lang']);
240
        $tmp->string = $array['string'];
241
        $tmp->forcedstring = $array['forcedstring'];
242
        return $tmp;
243
    }
244
 
245
    /**
246
     * Prepares the lang_string for sleep and stores only the forcedstring and
247
     * string properties... the string cannot be regenerated so we need to ensure
248
     * it is generated for this.
249
     *
250
     * @return array
251
     */
252
    public function __sleep() {
253
        $this->get_string();
254
        $this->forcedstring = true;
255
        return ['forcedstring', 'string', 'lang'];
256
    }
257
 
258
    /**
259
     * Returns the identifier.
260
     *
261
     * @return string
262
     */
263
    public function get_identifier(): string {
264
        return $this->identifier;
265
    }
266
 
267
    /**
268
     * Returns the component.
269
     *
270
     * @return string
271
     */
272
    public function get_component(): string {
273
        return $this->component;
274
    }
275
}
276
 
277
// Alias this class to the old name.
278
// This file will be autoloaded by the legacyclasses autoload system.
279
// In future all uses of this class will be corrected and the legacy references will be removed.
280
class_alias(lang_string::class, \lang_string::class);