Commit | Line | Data |
---|---|---|
4333580e DM |
1 | <?php |
2 | ||
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
18 | /** | |
19 | * Advanced grading methods support | |
20 | * | |
21 | * @package core | |
22 | * @subpackage grading | |
23 | * @copyright 2011 David Mudrak <david@moodle.com> | |
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
25 | */ | |
26 | ||
27 | defined('MOODLE_INTERNAL') || die(); | |
28 | ||
29 | /** | |
30 | * Factory method returning an instance of the grading manager | |
31 | * | |
217116d4 DM |
32 | * There are basically ways how to use this factory method. If the area record |
33 | * id is known to the caller, get the manager for that area by providing just | |
34 | * the id. If the area record id is not know, the context, component and area name | |
35 | * can be provided. Note that null values are allowed in the second case as the context, | |
36 | * component and the area name can be set explicitly later. | |
37 | * | |
38 | * @example $manager = get_grading_manager($areaid); | |
39 | * @example $manager = get_grading_manager(get_system_context()); | |
40 | * @example $manager = get_grading_manager($context, 'mod_assignment', 'submission'); | |
41 | * @param stdClass|int|null $context or $areaid if $areaid is passed, no other parameter is needed | |
42 | * @param string|null $component the frankenstyle name of the component | |
43 | * @param string|null $area the name of the gradable area | |
4333580e DM |
44 | * @return grading_manager |
45 | */ | |
fb13a148 DM |
46 | function get_grading_manager($context_or_areaid = null, $component = null, $area = null) { |
47 | global $DB; | |
4333580e DM |
48 | |
49 | $manager = new grading_manager(); | |
50 | ||
fb13a148 DM |
51 | if (is_object($context_or_areaid)) { |
52 | $context = $context_or_areaid; | |
53 | } else { | |
54 | $context = null; | |
55 | ||
56 | if (is_numeric($context_or_areaid)) { | |
57 | $manager->load($context_or_areaid); | |
58 | return $manager; | |
59 | } | |
60 | } | |
61 | ||
4333580e DM |
62 | if (!is_null($context)) { |
63 | $manager->set_context($context); | |
64 | } | |
65 | ||
66 | if (!is_null($component)) { | |
67 | $manager->set_component($component); | |
68 | } | |
69 | ||
8a4acb3a DM |
70 | if (!is_null($area)) { |
71 | $manager->set_area($area); | |
4333580e DM |
72 | } |
73 | ||
74 | return $manager; | |
75 | } | |
76 | ||
77 | /** | |
78 | * General class providing access to common grading features | |
79 | * | |
9b8550f8 DM |
80 | * Grading manager provides access to the particular grading method controller |
81 | * in that area. | |
82 | * | |
4333580e DM |
83 | * Fully initialized instance of the grading manager operates over a single |
84 | * gradable area. It is possible to work with a partially initialized manager | |
8a4acb3a DM |
85 | * that knows just context and component without known area, for example. |
86 | * It is also possible to change context, component and area of an existing | |
4333580e DM |
87 | * manager. Such pattern is used when copying form definitions, for example. |
88 | */ | |
89 | class grading_manager { | |
90 | ||
91 | /** @var stdClass the context */ | |
92 | protected $context; | |
93 | ||
94 | /** @var string the frankenstyle name of the component */ | |
95 | protected $component; | |
96 | ||
97 | /** @var string the name of the gradable area */ | |
8a4acb3a | 98 | protected $area; |
4333580e | 99 | |
9b8550f8 DM |
100 | /** @var stdClass|false|null the raw record from {grading_areas}, false if does not exist, null if invalidated cache */ |
101 | private $areacache = null; | |
102 | ||
21d37aa6 DM |
103 | /** |
104 | * @return stdClass grading manager context | |
105 | */ | |
106 | public function get_context() { | |
107 | return $this->context; | |
108 | } | |
109 | ||
4333580e DM |
110 | /** |
111 | * Sets the context the manager operates on | |
112 | * | |
113 | * @param stdClass $context | |
114 | */ | |
115 | public function set_context(stdClass $context) { | |
9b8550f8 | 116 | $this->areacache = null; |
4333580e DM |
117 | $this->context = $context; |
118 | } | |
119 | ||
21d37aa6 DM |
120 | /** |
121 | * @return string grading manager component | |
122 | */ | |
123 | public function get_component() { | |
124 | return $this->component; | |
125 | } | |
126 | ||
4333580e DM |
127 | /** |
128 | * Sets the component the manager operates on | |
129 | * | |
130 | * @param string $component the frankenstyle name of the component | |
131 | */ | |
132 | public function set_component($component) { | |
9b8550f8 DM |
133 | $this->areacache = null; |
134 | list($type, $name) = normalize_component($component); | |
135 | $this->component = $type.'_'.$name; | |
4333580e DM |
136 | } |
137 | ||
21d37aa6 DM |
138 | /** |
139 | * @return string grading manager area name | |
140 | */ | |
141 | public function get_area() { | |
142 | return $this->area; | |
143 | } | |
144 | ||
4333580e | 145 | /** |
8a4acb3a | 146 | * Sets the area the manager operates on |
4333580e | 147 | * |
8a4acb3a | 148 | * @param string $area the name of the gradable area |
4333580e | 149 | */ |
8a4acb3a | 150 | public function set_area($area) { |
9b8550f8 | 151 | $this->areacache = null; |
8a4acb3a | 152 | $this->area = $area; |
4333580e DM |
153 | } |
154 | ||
6832a102 DM |
155 | /** |
156 | * Returns a text describing the context and the component | |
157 | * | |
158 | * At the moment this works for gradable areas in course modules. In the future, this | |
159 | * method should be improved so it works for other contexts (blocks, gradebook items etc) | |
160 | * or subplugins. | |
161 | * | |
162 | * @return string | |
163 | */ | |
164 | public function get_component_title() { | |
165 | ||
166 | $this->ensure_isset(array('context', 'component')); | |
6832a102 | 167 | |
fde33804 DM |
168 | if ($this->get_context()->contextlevel == CONTEXT_SYSTEM) { |
169 | if ($this->get_component() == 'core_grading') { | |
170 | $title = ''; // we are in the bank UI | |
171 | } else { | |
172 | throw new coding_exception('Unsupported component at the system context'); | |
173 | } | |
174 | ||
175 | } else if ($this->get_context()->contextlevel >= CONTEXT_COURSE) { | |
176 | list($context, $course, $cm) = get_context_info_array($this->get_context()->id); | |
177 | ||
178 | if (!empty($cm->name)) { | |
179 | $title = $cm->name; | |
180 | } else { | |
181 | debugging('Gradable areas are currently supported at the course module level only', DEBUG_DEVELOPER); | |
182 | $title = $this->get_component(); | |
183 | } | |
184 | ||
6832a102 | 185 | } else { |
fde33804 | 186 | throw new coding_exception('Unsupported gradable area context level'); |
6832a102 DM |
187 | } |
188 | ||
189 | return $title; | |
190 | } | |
191 | ||
192 | /** | |
193 | * Returns the localized title of the currently set area | |
194 | * | |
195 | * @return string | |
196 | */ | |
197 | public function get_area_title() { | |
198 | ||
fde33804 DM |
199 | if ($this->get_context()->contextlevel == CONTEXT_SYSTEM) { |
200 | return ''; | |
201 | ||
202 | } else if ($this->get_context()->contextlevel >= CONTEXT_COURSE) { | |
203 | $this->ensure_isset(array('context', 'component', 'area')); | |
204 | $areas = $this->get_available_areas(); | |
205 | if (array_key_exists($this->get_area(), $areas)) { | |
206 | return $areas[$this->get_area()]; | |
207 | } else { | |
208 | debugging('Unknown area!'); | |
209 | return '???'; | |
210 | } | |
6832a102 | 211 | |
fde33804 DM |
212 | } else { |
213 | throw new coding_exception('Unsupported context level'); | |
214 | } | |
6832a102 DM |
215 | } |
216 | ||
fb13a148 DM |
217 | /** |
218 | * Loads the gradable area info from the database | |
219 | * | |
220 | * @param int $areaid | |
221 | */ | |
222 | public function load($areaid) { | |
223 | global $DB; | |
224 | ||
225 | $this->areacache = $DB->get_record('grading_areas', array('id' => $areaid), '*', MUST_EXIST); | |
226 | $this->context = get_context_instance_by_id($this->areacache->contextid, MUST_EXIST); | |
227 | $this->component = $this->areacache->component; | |
228 | $this->area = $this->areacache->areaname; | |
229 | } | |
230 | ||
4333580e | 231 | /** |
bb50c376 DM |
232 | * Returns the list of installed grading plugins together, optionally extended |
233 | * with a simple direct grading. | |
6c9e506c DM |
234 | * |
235 | * @param bool $includenone should the 'Simple direct grading' be included | |
4333580e DM |
236 | * @return array of the (string)name => (string)localized title of the method |
237 | */ | |
bb50c376 | 238 | public static function available_methods($includenone = true) { |
4333580e | 239 | |
6c9e506c DM |
240 | if ($includenone) { |
241 | $list = array('' => get_string('gradingmethodnone', 'core_grading')); | |
242 | } else { | |
243 | $list = array(); | |
244 | } | |
245 | ||
246 | foreach (get_plugin_list('gradingform') as $name => $location) { | |
247 | $list[$name] = get_string('pluginname', 'gradingform_'.$name); | |
248 | } | |
249 | ||
250 | return $list; | |
4333580e DM |
251 | } |
252 | ||
bb50c376 DM |
253 | /** |
254 | * Returns the list of available grading methods in the given context | |
255 | * | |
256 | * Currently this is just a static list obtained from {@link self::available_methods()}. | |
257 | * In the future, the list of available methods may be controlled per-context. | |
258 | * | |
259 | * Requires the context property to be set in advance. | |
260 | * | |
261 | * @param bool $includenone should the 'Simple direct grading' be included | |
262 | * @return array of the (string)name => (string)localized title of the method | |
263 | */ | |
264 | public function get_available_methods($includenone = true) { | |
265 | $this->ensure_isset(array('context')); | |
266 | return self::available_methods($includenone); | |
267 | } | |
268 | ||
269 | /** | |
270 | * Returns the list of gradable areas provided by the given component | |
271 | * | |
272 | * This performs a callback to the library of the relevant plugin to obtain | |
273 | * the list of supported areas. | |
274 | * | |
275 | * @param string $component normalized component name | |
276 | * @return array of (string)areacode => (string)localized title of the area | |
277 | */ | |
278 | public static function available_areas($component) { | |
279 | global $CFG; | |
280 | ||
281 | list($plugintype, $pluginname) = normalize_component($component); | |
282 | ||
283 | if ($component === 'core_grading') { | |
284 | return array(); | |
285 | ||
286 | } else if ($plugintype === 'mod') { | |
287 | return plugin_callback('mod', $pluginname, 'grading', 'areas_list', null, array()); | |
288 | ||
289 | } else { | |
290 | throw new coding_exception('Unsupported area location'); | |
291 | } | |
292 | } | |
293 | ||
294 | ||
4333580e DM |
295 | /** |
296 | * Returns the list of gradable areas in the given context and component | |
297 | * | |
298 | * This performs a callback to the library of the relevant plugin to obtain | |
299 | * the list of supported areas. | |
300 | * @return array of (string)areacode => (string)localized title of the area | |
301 | */ | |
302 | public function get_available_areas() { | |
303 | global $CFG; | |
304 | ||
305 | $this->ensure_isset(array('context', 'component')); | |
306 | ||
9e4eb676 DM |
307 | if ($this->get_context()->contextlevel == CONTEXT_SYSTEM) { |
308 | if ($this->get_component() !== 'core_grading') { | |
309 | throw new coding_exception('Unsupported component at the system context'); | |
310 | } else { | |
311 | return array(); | |
312 | } | |
313 | ||
bb50c376 | 314 | } else if ($this->get_context()->contextlevel == CONTEXT_MODULE) { |
9e4eb676 | 315 | list($context, $course, $cm) = get_context_info_array($this->get_context()->id); |
bb50c376 | 316 | return self::available_areas('mod_'.$cm->modname); |
9e4eb676 DM |
317 | |
318 | } else { | |
319 | throw new coding_exception('Unsupported gradable area context level'); | |
320 | } | |
4333580e DM |
321 | } |
322 | ||
323 | /** | |
8a4acb3a | 324 | * Returns the currently active grading method in the gradable area |
4333580e | 325 | * |
64402867 | 326 | * @return string|null the name of the grading plugin of null if it has not been set |
4333580e | 327 | */ |
8a4acb3a | 328 | public function get_active_method() { |
64402867 DM |
329 | global $DB; |
330 | ||
331 | $this->ensure_isset(array('context', 'component', 'area')); | |
332 | ||
333 | // get the current grading area record if it exists | |
9b8550f8 DM |
334 | if (is_null($this->areacache)) { |
335 | $this->areacache = $DB->get_record('grading_areas', array( | |
336 | 'contextid' => $this->context->id, | |
337 | 'component' => $this->component, | |
338 | 'areaname' => $this->area), | |
339 | '*', IGNORE_MISSING); | |
340 | } | |
64402867 | 341 | |
9b8550f8 | 342 | if ($this->areacache === false) { |
64402867 DM |
343 | // no area record yet |
344 | return null; | |
345 | } | |
346 | ||
9b8550f8 | 347 | return $this->areacache->activemethod; |
64402867 DM |
348 | } |
349 | ||
350 | /** | |
351 | * Sets the currently active grading method in the gradable area | |
352 | * | |
353 | * @param string $method the method name, eg 'rubric' (must be available) | |
3bd217aa | 354 | * @return bool true if the method changed or was just set, false otherwise |
64402867 DM |
355 | */ |
356 | public function set_active_method($method) { | |
357 | global $DB; | |
358 | ||
8a4acb3a | 359 | $this->ensure_isset(array('context', 'component', 'area')); |
64402867 | 360 | |
8cd65f16 DM |
361 | // make sure the passed method is empty or a valid plugin name |
362 | if (empty($method)) { | |
363 | $method = null; | |
364 | } else { | |
365 | if ('gradingform_'.$method !== clean_param('gradingform_'.$method, PARAM_COMPONENT)) { | |
366 | throw new moodle_exception('invalid_method_name', 'core_grading'); | |
367 | } | |
368 | $available = $this->get_available_methods(false); | |
369 | if (!array_key_exists($method, $available)) { | |
370 | throw new moodle_exception('invalid_method_name', 'core_grading'); | |
371 | } | |
64402867 DM |
372 | } |
373 | ||
374 | // get the current grading area record if it exists | |
9b8550f8 DM |
375 | if (is_null($this->areacache)) { |
376 | $this->areacache = $DB->get_record('grading_areas', array( | |
377 | 'contextid' => $this->context->id, | |
378 | 'component' => $this->component, | |
379 | 'areaname' => $this->area), | |
380 | '*', IGNORE_MISSING); | |
381 | } | |
64402867 | 382 | |
3bd217aa DM |
383 | $methodchanged = false; |
384 | ||
9b8550f8 | 385 | if ($this->areacache === false) { |
64402867 DM |
386 | // no area record yet, create one with the active method set |
387 | $area = array( | |
388 | 'contextid' => $this->context->id, | |
389 | 'component' => $this->component, | |
390 | 'areaname' => $this->area, | |
391 | 'activemethod' => $method); | |
392 | $DB->insert_record('grading_areas', $area); | |
3bd217aa | 393 | $methodchanged = true; |
64402867 DM |
394 | |
395 | } else { | |
396 | // update the existing record if needed | |
8cd65f16 | 397 | if ($this->areacache->activemethod !== $method) { |
9b8550f8 | 398 | $DB->set_field('grading_areas', 'activemethod', $method, array('id' => $this->areacache->id)); |
3bd217aa | 399 | $methodchanged = true; |
64402867 DM |
400 | } |
401 | } | |
9b8550f8 DM |
402 | |
403 | $this->areacache = null; | |
3bd217aa DM |
404 | |
405 | return $methodchanged; | |
9b8550f8 DM |
406 | } |
407 | ||
408 | /** | |
409 | * Extends the settings navigation with the grading settings | |
410 | * | |
411 | * This function is called when the context for the page is an activity module with the | |
412 | * FEATURE_ADVANCED_GRADING and the user has the permission moodle/grade:managegradingforms. | |
413 | * | |
414 | * @param settings_navigation $settingsnav {@link settings_navigation} | |
415 | * @param navigation_node $modulenode {@link navigation_node} | |
416 | */ | |
417 | public function extend_settings_navigation(settings_navigation $settingsnav, navigation_node $modulenode=null) { | |
9b8550f8 DM |
418 | |
419 | $this->ensure_isset(array('context', 'component')); | |
420 | ||
421 | $areas = $this->get_available_areas(); | |
422 | ||
423 | if (empty($areas)) { | |
424 | // no money, no funny | |
425 | return; | |
8168299d | 426 | |
98a73bb7 DM |
427 | } else if (count($areas) == 1) { |
428 | // make just a single node for the management screen | |
429 | $areatitle = reset($areas); | |
430 | $areaname = key($areas); | |
9b8550f8 DM |
431 | $this->set_area($areaname); |
432 | $method = $this->get_active_method(); | |
98a73bb7 DM |
433 | $managementnode = $modulenode->add(get_string('gradingmanagement', 'core_grading'), |
434 | $this->get_management_url(), settings_navigation::TYPE_CUSTOM); | |
435 | if ($method) { | |
436 | $controller = $this->get_controller($method); | |
437 | $controller->extend_settings_navigation($settingsnav, $managementnode); | |
9b8550f8 DM |
438 | } |
439 | ||
98a73bb7 DM |
440 | } else { |
441 | // make management screen node for each area | |
442 | $managementnode = $modulenode->add(get_string('gradingmanagement', 'core_grading'), | |
443 | null, settings_navigation::TYPE_CUSTOM); | |
444 | foreach ($areas as $areaname => $areatitle) { | |
445 | $this->set_area($areaname); | |
446 | $method = $this->get_active_method(); | |
447 | $node = $managementnode->add($areatitle, | |
448 | $this->get_management_url(), settings_navigation::TYPE_CUSTOM); | |
449 | if ($method) { | |
450 | $controller = $this->get_controller($method); | |
451 | $controller->extend_settings_navigation($settingsnav, $node); | |
452 | } | |
9b8550f8 | 453 | } |
9b8550f8 DM |
454 | } |
455 | } | |
456 | ||
457 | /** | |
458 | * Returns the given method's controller in the gradable area | |
459 | * | |
460 | * @param string $method the method name, eg 'rubric' (must be available) | |
461 | * @return grading_controller | |
462 | */ | |
463 | public function get_controller($method) { | |
464 | global $CFG; | |
465 | ||
466 | $this->ensure_isset(array('context', 'component', 'area')); | |
467 | ||
468 | // make sure the passed method is a valid plugin name | |
469 | if ('gradingform_'.$method !== clean_param('gradingform_'.$method, PARAM_COMPONENT)) { | |
470 | throw new moodle_exception('invalid_method_name', 'core_grading'); | |
471 | } | |
472 | $available = $this->get_available_methods(false); | |
473 | if (!array_key_exists($method, $available)) { | |
474 | throw new moodle_exception('invalid_method_name', 'core_grading'); | |
475 | } | |
476 | ||
477 | // get the current grading area record if it exists | |
478 | if (is_null($this->areacache)) { | |
479 | $this->areacache = $DB->get_record('grading_areas', array( | |
480 | 'contextid' => $this->context->id, | |
481 | 'component' => $this->component, | |
482 | 'areaname' => $this->area), | |
483 | '*', IGNORE_MISSING); | |
484 | } | |
485 | ||
486 | if ($this->areacache === false) { | |
487 | // no area record yet, create one | |
488 | $area = array( | |
489 | 'contextid' => $this->context->id, | |
490 | 'component' => $this->component, | |
491 | 'areaname' => $this->area); | |
492 | $areaid = $DB->insert_record('grading_areas', $area); | |
493 | // reload the cache | |
494 | $this->areacache = $DB->get_record('grading_areas', array('id' => $areaid), '*', MUST_EXIST); | |
495 | } | |
496 | ||
497 | require_once($CFG->dirroot.'/grade/grading/form/'.$method.'/lib.php'); | |
3e43eff5 | 498 | $classname = 'gradingform_'.$method.'_controller'; |
9b8550f8 DM |
499 | |
500 | return new $classname($this->context, $this->component, $this->area, $this->areacache->id); | |
4333580e DM |
501 | } |
502 | ||
18e6298c MG |
503 | /** |
504 | * Returns the controller for the active method if it is available | |
03d448e5 DM |
505 | * |
506 | * @return null|grading_controller | |
18e6298c MG |
507 | */ |
508 | public function get_active_controller() { | |
509 | if ($gradingmethod = $this->get_active_method()) { | |
510 | $controller = $this->get_controller($gradingmethod); | |
511 | if ($controller->is_form_available()) { | |
512 | return $controller; | |
513 | } | |
514 | } | |
515 | return null; | |
516 | } | |
517 | ||
03d448e5 DM |
518 | /** |
519 | * Returns the URL of the grading area management page | |
520 | * | |
521 | * @param moodle_url $returnurl optional URL of the page where the user should be sent back to | |
522 | * @return moodle_url | |
523 | */ | |
98a73bb7 | 524 | public function get_management_url(moodle_url $returnurl = null) { |
03d448e5 DM |
525 | |
526 | $this->ensure_isset(array('context', 'component')); | |
527 | ||
528 | if ($this->areacache) { | |
529 | $params = array('areaid' => $this->areacache->id); | |
530 | } else { | |
531 | $params = array('contextid' => $this->context->id, 'component' => $this->component); | |
98a73bb7 DM |
532 | if ($this->area) { |
533 | $params['area'] = $this->area; | |
6832a102 | 534 | } |
03d448e5 DM |
535 | } |
536 | ||
537 | if (!is_null($returnurl)) { | |
538 | $params['returnurl'] = $returnurl->out(false); | |
539 | } | |
540 | ||
6832a102 | 541 | return new moodle_url('/grade/grading/manage.php', $params); |
03d448e5 DM |
542 | } |
543 | ||
fde33804 DM |
544 | /** |
545 | * Creates a new shared area to hold a grading form template | |
546 | * | |
547 | * Shared area are implemented as virtual gradable areas at the system level context | |
548 | * with the component set to core_grading and unique random area name. | |
549 | * | |
550 | * @param string $method the name of the plugin we create the area for | |
551 | * @return int the new area id | |
552 | */ | |
553 | public function create_shared_area($method) { | |
554 | global $DB; | |
555 | ||
556 | // generate some unique random name for the new area | |
557 | $name = $method . '_' . sha1(rand().uniqid($method, true)); | |
558 | // create new area record | |
559 | $area = array( | |
dd736a87 | 560 | 'contextid' => context_system::instance()->id, |
fde33804 DM |
561 | 'component' => 'core_grading', |
562 | 'areaname' => $name, | |
563 | 'activemethod' => $method); | |
564 | return $DB->insert_record('grading_areas', $area); | |
565 | } | |
566 | ||
20836db9 DM |
567 | /** |
568 | * Helper method to tokenize the given string | |
569 | * | |
570 | * Splits the given string into smaller strings. This is a helper method for | |
571 | * full text searching in grading forms. If the given string is surrounded with | |
572 | * double quotes, the resulting array consists of a single item containing the | |
573 | * quoted content. | |
574 | * | |
575 | * Otherwise, string like 'grammar, english language' would be tokenized into | |
576 | * the three tokens 'grammar', 'english', 'language'. | |
577 | * | |
578 | * One-letter tokens like are dropped in non-phrase mode. Repeated tokens are | |
579 | * returned just once. | |
580 | * | |
581 | * @param string $needle | |
582 | * @return array | |
583 | */ | |
584 | public static function tokenize($needle) { | |
585 | ||
586 | // check if we are searching for the exact phrase | |
587 | if (preg_match('/^[\s]*"[\s]*(.*?)[\s]*"[\s]*$/', $needle, $matches)) { | |
588 | $token = $matches[1]; | |
589 | if ($token === '') { | |
590 | return array(); | |
591 | } else { | |
592 | return array($token); | |
593 | } | |
594 | } | |
595 | ||
596 | // split the needle into smaller parts separated by non-word characters | |
597 | $tokens = preg_split("/\W/u", $needle); | |
598 | // keep just non-empty parts | |
599 | $tokens = array_filter($tokens); | |
600 | // distinct | |
601 | $tokens = array_unique($tokens); | |
602 | // drop one-letter tokens | |
603 | foreach ($tokens as $ix => $token) { | |
604 | if (strlen($token) == 1) { | |
605 | unset($tokens[$ix]); | |
606 | } | |
607 | } | |
608 | ||
609 | return array_values($tokens); | |
610 | } | |
611 | ||
9b8550f8 | 612 | //////////////////////////////////////////////////////////////////////////// |
64402867 | 613 | |
4333580e DM |
614 | /** |
615 | * Make sure that the given properties were set to some not-null value | |
616 | * | |
617 | * @param array $properties the list of properties | |
618 | * @throws coding_exception | |
619 | */ | |
620 | private function ensure_isset(array $properties) { | |
621 | foreach ($properties as $property) { | |
622 | if (!isset($this->$property)) { | |
9b8550f8 | 623 | throw new coding_exception('The property "'.$property.'" is not set.'); |
4333580e DM |
624 | } |
625 | } | |
626 | } | |
627 | } |