forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MDL-40299 textlib conversion to core_text and core_collator
- Loading branch information
Showing
13 changed files
with
1,685 additions
and
1,584 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,307 @@ | ||
<?php | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
/** | ||
* Defines string apis | ||
* | ||
* @package core | ||
* @copyright 2011 Sam Hemelryk | ||
* 2012 Petr Skoda | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
defined('MOODLE_INTERNAL') || die(); | ||
|
||
/** | ||
* A collator class with static methods that can be used for sorting. | ||
* | ||
* @package core | ||
* @copyright 2011 Sam Hemelryk | ||
* 2012 Petr Skoda | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class core_collator { | ||
/** @const compare items using general PHP comparison, equivalent to Collator::SORT_REGULAR, this may bot be locale aware! */ | ||
const SORT_REGULAR = 0; | ||
|
||
/** @const compare items as strings, equivalent to Collator::SORT_STRING */ | ||
const SORT_STRING = 1; | ||
|
||
/** @const compare items as numbers, equivalent to Collator::SORT_NUMERIC */ | ||
const SORT_NUMERIC = 2; | ||
|
||
/** @const compare items like natsort(), equivalent to SORT_NATURAL */ | ||
const SORT_NATURAL = 6; | ||
|
||
/** @const do not ignore case when sorting, use bitwise "|" with SORT_NATURAL or SORT_STRING, equivalent to Collator::UPPER_FIRST */ | ||
const CASE_SENSITIVE = 64; | ||
|
||
/** @var Collator|false|null **/ | ||
protected static $collator = null; | ||
|
||
/** @var string|null The locale that was used in instantiating the current collator **/ | ||
protected static $locale = null; | ||
|
||
/** | ||
* Prevent class instances, all methods are static. | ||
*/ | ||
private function __construct() { | ||
} | ||
|
||
/** | ||
* Ensures that a collator is available and created | ||
* | ||
* @return bool Returns true if collation is available and ready | ||
*/ | ||
protected static function ensure_collator_available() { | ||
$locale = get_string('locale', 'langconfig'); | ||
if (is_null(self::$collator) || $locale != self::$locale) { | ||
self::$collator = false; | ||
self::$locale = $locale; | ||
if (class_exists('Collator', false)) { | ||
$collator = new Collator($locale); | ||
if (!empty($collator) && $collator instanceof Collator) { | ||
// Check for non fatal error messages. This has to be done immediately | ||
// after instantiation as any further calls to collation will cause | ||
// it to reset to 0 again (or another error code if one occurred) | ||
$errorcode = $collator->getErrorCode(); | ||
$errormessage = $collator->getErrorMessage(); | ||
// Check for an error code, 0 means no error occurred | ||
if ($errorcode !== 0) { | ||
// Get the actual locale being used, e.g. en, he, zh | ||
$localeinuse = $collator->getLocale(Locale::ACTUAL_LOCALE); | ||
// Check for the common fallback warning error codes. If this occurred | ||
// there is normally little to worry about: | ||
// - U_USING_DEFAULT_WARNING (127) - default fallback locale used (pt => UCA) | ||
// - U_USING_FALLBACK_WARNING (128) - fallback locale used (de_CH => de) | ||
// (UCA: Unicode Collation Algorithm http://unicode.org/reports/tr10/) | ||
if ($errorcode === -127 || $errorcode === -128) { | ||
// Check if the locale in use is UCA default one ('root') or | ||
// if it is anything like the locale we asked for | ||
if ($localeinuse !== 'root' && strpos($locale, $localeinuse) !== 0) { | ||
// The locale we asked for is completely different to the locale | ||
// we have received, let the user know via debugging | ||
debugging('Invalid locale: "' . $locale . '", with warning (not fatal) "' . $errormessage . | ||
'", falling back to "' . $collator->getLocale(Locale::VALID_LOCALE) . '"'); | ||
} else { | ||
// Nothing to do here, this is expected! | ||
// The Moodle locale setting isn't what the collator expected but | ||
// it is smart enough to match the first characters of our locale | ||
// to find the correct locale or to use UCA collation | ||
} | ||
} else { | ||
// We've received some other sort of non fatal warning - let the | ||
// user know about it via debugging. | ||
debugging('Problem with locale: "' . $locale . '", with message "' . $errormessage . | ||
'", falling back to "' . $collator->getLocale(Locale::VALID_LOCALE) . '"'); | ||
} | ||
} | ||
// Store the collator object now that we can be sure it is in a workable condition | ||
self::$collator = $collator; | ||
} else { | ||
// Fatal error while trying to instantiate the collator... something went wrong | ||
debugging('Error instantiating collator for locale: "' . $locale . '", with error [' . | ||
intl_get_error_code() . '] ' . intl_get_error_message($collator)); | ||
} | ||
} | ||
} | ||
return (self::$collator instanceof Collator); | ||
} | ||
|
||
/** | ||
* Restore array contents keeping new keys. | ||
* @static | ||
* @param array $arr | ||
* @param array $original | ||
* @return void modifies $arr | ||
*/ | ||
protected static function restore_array(array &$arr, array &$original) { | ||
foreach ($arr as $key => $ignored) { | ||
$arr[$key] = $original[$key]; | ||
} | ||
} | ||
|
||
/** | ||
* Normalise numbers in strings for natural sorting comparisons. | ||
* @static | ||
* @param string $string | ||
* @return string string with normalised numbers | ||
*/ | ||
protected static function naturalise($string) { | ||
return preg_replace_callback('/[0-9]+/', array('collatorlib', 'callback_naturalise'), $string); | ||
} | ||
|
||
/** | ||
* @internal | ||
* @static | ||
* @param array $matches | ||
* @return string | ||
*/ | ||
public static function callback_naturalise($matches) { | ||
return str_pad($matches[0], 20, '0', STR_PAD_LEFT); | ||
} | ||
|
||
/** | ||
* Locale aware sorting, the key associations are kept, values are sorted alphabetically. | ||
* | ||
* @param array $arr array to be sorted (reference) | ||
* @param int $sortflag One of collatorlib::SORT_NUMERIC, collatorlib::SORT_STRING, collatorlib::SORT_NATURAL, collatorlib::SORT_REGULAR | ||
* optionally "|" collatorlib::CASE_SENSITIVE | ||
* @return bool True on success | ||
*/ | ||
public static function asort(array &$arr, $sortflag = collatorlib::SORT_STRING) { | ||
if (empty($arr)) { | ||
// nothing to do | ||
return true; | ||
} | ||
|
||
$original = null; | ||
|
||
$casesensitive = (bool)($sortflag & collatorlib::CASE_SENSITIVE); | ||
$sortflag = ($sortflag & ~collatorlib::CASE_SENSITIVE); | ||
if ($sortflag != collatorlib::SORT_NATURAL and $sortflag != collatorlib::SORT_STRING) { | ||
$casesensitive = false; | ||
} | ||
|
||
if (self::ensure_collator_available()) { | ||
if ($sortflag == collatorlib::SORT_NUMERIC) { | ||
$flag = Collator::SORT_NUMERIC; | ||
|
||
} else if ($sortflag == collatorlib::SORT_REGULAR) { | ||
$flag = Collator::SORT_REGULAR; | ||
|
||
} else { | ||
$flag = Collator::SORT_STRING; | ||
} | ||
|
||
if ($sortflag == collatorlib::SORT_NATURAL) { | ||
$original = $arr; | ||
if ($sortflag == collatorlib::SORT_NATURAL) { | ||
foreach ($arr as $key => $value) { | ||
$arr[$key] = self::naturalise((string)$value); | ||
} | ||
} | ||
} | ||
if ($casesensitive) { | ||
self::$collator->setAttribute(Collator::CASE_FIRST, Collator::UPPER_FIRST); | ||
} else { | ||
self::$collator->setAttribute(Collator::CASE_FIRST, Collator::OFF); | ||
} | ||
$result = self::$collator->asort($arr, $flag); | ||
if ($original) { | ||
self::restore_array($arr, $original); | ||
} | ||
return $result; | ||
} | ||
|
||
// try some fallback that works at least for English | ||
|
||
if ($sortflag == collatorlib::SORT_NUMERIC) { | ||
return asort($arr, SORT_NUMERIC); | ||
|
||
} else if ($sortflag == collatorlib::SORT_REGULAR) { | ||
return asort($arr, SORT_REGULAR); | ||
} | ||
|
||
if (!$casesensitive) { | ||
$original = $arr; | ||
foreach ($arr as $key => $value) { | ||
$arr[$key] = textlib::strtolower($value); | ||
} | ||
} | ||
|
||
if ($sortflag == collatorlib::SORT_NATURAL) { | ||
$result = natsort($arr); | ||
|
||
} else { | ||
$result = asort($arr, SORT_LOCALE_STRING); | ||
} | ||
|
||
if ($original) { | ||
self::restore_array($arr, $original); | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
/** | ||
* Locale aware sort of objects by a property in common to all objects | ||
* | ||
* @param array $objects An array of objects to sort (handled by reference) | ||
* @param string $property The property to use for comparison | ||
* @param int $sortflag One of collatorlib::SORT_NUMERIC, collatorlib::SORT_STRING, collatorlib::SORT_NATURAL, collatorlib::SORT_REGULAR | ||
* optionally "|" collatorlib::CASE_SENSITIVE | ||
* @return bool True on success | ||
*/ | ||
public static function asort_objects_by_property(array &$objects, $property, $sortflag = collatorlib::SORT_STRING) { | ||
$original = $objects; | ||
foreach ($objects as $key => $object) { | ||
$objects[$key] = $object->$property; | ||
} | ||
$result = self::asort($objects, $sortflag); | ||
self::restore_array($objects, $original); | ||
return $result; | ||
} | ||
|
||
/** | ||
* Locale aware sort of objects by a method in common to all objects | ||
* | ||
* @param array $objects An array of objects to sort (handled by reference) | ||
* @param string $method The method to call to generate a value for comparison | ||
* @param int $sortflag One of collatorlib::SORT_NUMERIC, collatorlib::SORT_STRING, collatorlib::SORT_NATURAL, collatorlib::SORT_REGULAR | ||
* optionally "|" collatorlib::CASE_SENSITIVE | ||
* @return bool True on success | ||
*/ | ||
public static function asort_objects_by_method(array &$objects, $method, $sortflag = collatorlib::SORT_STRING) { | ||
$original = $objects; | ||
foreach ($objects as $key => $object) { | ||
$objects[$key] = $object->{$method}(); | ||
} | ||
$result = self::asort($objects, $sortflag); | ||
self::restore_array($objects, $original); | ||
return $result; | ||
} | ||
|
||
/** | ||
* Locale aware sorting, the key associations are kept, keys are sorted alphabetically. | ||
* | ||
* @param array $arr array to be sorted (reference) | ||
* @param int $sortflag One of collatorlib::SORT_NUMERIC, collatorlib::SORT_STRING, collatorlib::SORT_NATURAL, collatorlib::SORT_REGULAR | ||
* optionally "|" collatorlib::CASE_SENSITIVE | ||
* @return bool True on success | ||
*/ | ||
public static function ksort(array &$arr, $sortflag = collatorlib::SORT_STRING) { | ||
$keys = array_keys($arr); | ||
if (!self::asort($keys, $sortflag)) { | ||
return false; | ||
} | ||
// This is a bit slow, but we need to keep the references | ||
$original = $arr; | ||
$arr = array(); // Surprisingly this does not break references outside | ||
foreach ($keys as $key) { | ||
$arr[$key] = $original[$key]; | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
|
||
/** | ||
* Legacy collatorlib. | ||
* @deprecated since 2.6, use core_collator:: instead. | ||
*/ | ||
class collatorlib extends core_collator { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.