diff options
| -rw-r--r-- | app/Elements/DemographicDataType.php | 2 | ||||
| -rw-r--r-- | app/Elements/HierarchicalRelationship.php | 2 | ||||
| -rw-r--r-- | app/Elements/LanguageId.php | 2 | ||||
| -rw-r--r-- | app/Elements/SourceMediaType.php | 2 | ||||
| -rw-r--r-- | app/Elements/TempleCode.php | 2 | ||||
| -rw-r--r-- | app/Functions/FunctionsEdit.php | 3 | ||||
| -rw-r--r-- | app/Functions/FunctionsPrint.php | 8 | ||||
| -rw-r--r-- | app/GedcomRecord.php | 2 | ||||
| -rw-r--r-- | app/GedcomTag.php | 264 | ||||
| -rw-r--r-- | app/Http/RequestHandlers/TreePreferencesPage.php | 76 | ||||
| -rw-r--r-- | app/Http/RequestHandlers/TreePrivacyPage.php | 4 | ||||
| -rw-r--r-- | app/I18N.php | 20 | ||||
| -rw-r--r-- | app/Module/ChartsBlockModule.php | 2 | ||||
| -rw-r--r-- | app/Module/ColorsTheme.php | 2 | ||||
| -rw-r--r-- | app/Module/FamilyTreeStatisticsModule.php | 2 | ||||
| -rw-r--r-- | app/Module/ModuleThemeTrait.php | 2 | ||||
| -rw-r--r-- | app/Module/TopSurnamesModule.php | 2 | ||||
| -rw-r--r-- | app/Services/ModuleService.php | 22 | ||||
| -rw-r--r-- | app/Statistics/Repository/IndividualRepository.php | 2 | ||||
| -rw-r--r-- | phpstan-baseline.neon | 7 | ||||
| -rw-r--r-- | tests/app/I18NTest.php | 18 |
21 files changed, 122 insertions, 324 deletions
diff --git a/app/Elements/DemographicDataType.php b/app/Elements/DemographicDataType.php index d1fe599aa3..5e52c725b2 100644 --- a/app/Elements/DemographicDataType.php +++ b/app/Elements/DemographicDataType.php @@ -56,7 +56,7 @@ class DemographicDataType extends AbstractElement 'CITI' => /* I18N: Type of demographic data */ I18N::translate('citizen'), ]; - uasort($values, [I18N::class, 'strcasecmp']); + uasort($values, I18N::comparator()); return $values; } diff --git a/app/Elements/HierarchicalRelationship.php b/app/Elements/HierarchicalRelationship.php index 644ffed319..9b4aa646e6 100644 --- a/app/Elements/HierarchicalRelationship.php +++ b/app/Elements/HierarchicalRelationship.php @@ -59,7 +59,7 @@ class HierarchicalRelationship extends AbstractElement 'CULT' => /* I18N: Type of location hierarchy */ I18N::translate('cultural'), ]; - uasort($values, [I18N::class, 'strcasecmp']); + uasort($values, I18N::comparator()); return $values; } diff --git a/app/Elements/LanguageId.php b/app/Elements/LanguageId.php index 1942c6c7c8..543cdcdfe1 100644 --- a/app/Elements/LanguageId.php +++ b/app/Elements/LanguageId.php @@ -214,7 +214,7 @@ class LanguageId extends AbstractElement 'Yiddish' => (new LocaleYi())->endonym(), ]; - uasort($values, [I18N::class, 'strcasecmp']); + uasort($values, I18N::comparator()); return $values; } diff --git a/app/Elements/SourceMediaType.php b/app/Elements/SourceMediaType.php index 909494293c..571442905a 100644 --- a/app/Elements/SourceMediaType.php +++ b/app/Elements/SourceMediaType.php @@ -77,7 +77,7 @@ class SourceMediaType extends AbstractElement 'video' => /* I18N: Type of media object */ I18N::translate('Video'), ]; - uasort($values, '\Fisharebest\Webtrees\I18N::strcasecmp'); + uasort($values, I18N::comparator()); return $values; } diff --git a/app/Elements/TempleCode.php b/app/Elements/TempleCode.php index 8ac67d4f76..b8f0530add 100644 --- a/app/Elements/TempleCode.php +++ b/app/Elements/TempleCode.php @@ -207,7 +207,7 @@ class TempleCode extends AbstractElement 'WINTE' => /* I18N: Location of an LDS church temple */ I18N::translate('Winter Quarters, Nebraska, United States'), ]; - uasort($values, [I18N::class, 'strcasecmp']); + uasort($values, I18N::comparator()); $values = ['' => I18N::translate('No temple - living ordinance')] + $values; return $values; diff --git a/app/Functions/FunctionsEdit.php b/app/Functions/FunctionsEdit.php index 18efd70eff..fc7484a437 100644 --- a/app/Functions/FunctionsEdit.php +++ b/app/Functions/FunctionsEdit.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Census\Census; use Fisharebest\Webtrees\Config; use Fisharebest\Webtrees\Date; +use Fisharebest\Webtrees\Elements\PafUid; use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Family; use Fisharebest\Webtrees\Gedcom; @@ -641,7 +642,7 @@ class FunctionsEdit } else { self::$tags[0] = $fact; if ($fact === '_UID') { - $fact .= ' ' . GedcomTag::createUid(); + $fact .= ' ' . (new PafUid(''))->default($tree); } // These new level 1 tags need to be turned into links if (in_array($fact, ['ALIA', 'ASSO'], true)) { diff --git a/app/Functions/FunctionsPrint.php b/app/Functions/FunctionsPrint.php index d24e341401..aa1ba2db7d 100644 --- a/app/Functions/FunctionsPrint.php +++ b/app/Functions/FunctionsPrint.php @@ -26,7 +26,6 @@ use Fisharebest\Webtrees\Family; use Fisharebest\Webtrees\Filter; use Fisharebest\Webtrees\Gedcom; use Fisharebest\Webtrees\GedcomRecord; -use Fisharebest\Webtrees\GedcomTag; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Media; @@ -561,12 +560,11 @@ class FunctionsPrint $addfacts = array_merge(self::checkFactUnique($uniquefacts, $usedfacts), $addfacts); $quickfacts = array_intersect($quickfacts, $addfacts); $translated_addfacts = []; + foreach ($addfacts as $addfact) { - $translated_addfacts[$addfact] = GedcomTag::getLabel($record->tag() . ':' . $addfact); + $translated_addfacts[$addfact] = Registry::elementFactory()->make($record->tag() . ':' . $addfact)->label(); } - uasort($translated_addfacts, static function (string $x, string $y): int { - return I18N::strcasecmp(I18N::translate($x), I18N::translate($y)); - }); + uasort($translated_addfacts, I18N::comparator()); echo view('edit/add-fact-row', [ 'add_facts' => $translated_addfacts, diff --git a/app/GedcomRecord.php b/app/GedcomRecord.php index 4a8b71f717..8a9d92c57b 100644 --- a/app/GedcomRecord.php +++ b/app/GedcomRecord.php @@ -135,7 +135,7 @@ class GedcomRecord return static function (GedcomRecord $x, GedcomRecord $y): int { if ($x->canShowName()) { if ($y->canShowName()) { - return I18N::strcasecmp($x->sortName(), $y->sortName()); + return I18N::comparator()($x->sortName(), $y->sortName()); } return -1; // only $y is private diff --git a/app/GedcomTag.php b/app/GedcomTag.php index 9a81b02662..2a69a53647 100644 --- a/app/GedcomTag.php +++ b/app/GedcomTag.php @@ -1283,268 +1283,4 @@ class GedcomTag I18N::translate('<span class="label">%1$s:</span> <span class="field" dir="auto">%2$s</span>', self::getLabel($tag), $value) . '</' . $element . '>'; } - - /** - * Get a list of facts, for use in the "fact picker" edit control - * - * @param string $fact_type - * - * @return array<string> - */ - public static function getPicklistFacts(string $fact_type): array - { - switch ($fact_type) { - case Individual::RECORD_TYPE: - $tags = [ - // Facts, attributes for individuals (no links to FAMs) - 'RESN', - 'NAME', - 'SEX', - 'BIRT', - 'CHR', - 'DEAT', - 'BURI', - 'CREM', - 'ADOP', - 'BAPM', - 'BARM', - 'BASM', - 'BLES', - 'CHRA', - 'CONF', - 'FCOM', - 'ORDN', - 'NATU', - 'EMIG', - 'IMMI', - 'CENS', - 'PROB', - 'WILL', - 'GRAD', - 'RETI', - 'EVEN', - 'CAST', - 'DSCR', - 'EDUC', - 'IDNO', - 'NATI', - 'NCHI', - 'NMR', - 'OCCU', - 'PROP', - 'RELI', - 'RESI', - 'SSN', - 'TITL', - 'FACT', - 'BAPL', - 'CONL', - 'ENDL', - 'SLGC', - 'SUBM', - 'ASSO', - 'ALIA', - 'ANCI', - 'DESI', - 'RFN', - 'AFN', - 'REFN', - 'RIN', - 'CHAN', - 'NOTE', - 'SHARED_NOTE', - 'SOUR', - 'OBJE', - // non standard tags - '_BRTM', - '_DEG', - '_DNA', - '_EYEC', - '_FNRL', - '_HAIR', - '_HEIG', - '_HNM', - '_HOL', - '_INTE', - '_MDCL', - '_MEDC', - '_MILI', - '_MILT', - '_NAME', - '_NAMS', - '_NLIV', - '_NMAR', - '_PRMN', - '_TODO', - '_UID', - '_WEIG', - '_YART', - ]; - break; - - case Family::RECORD_TYPE: - $tags = [ - // Facts for families, left out HUSB, WIFE & CHIL links - 'RESN', - 'ANUL', - 'CENS', - 'DIV', - 'DIVF', - 'ENGA', - 'MARB', - 'MARC', - 'MARR', - 'MARL', - 'MARS', - 'RESI', - 'EVEN', - 'NCHI', - 'SUBM', - 'SLGS', - 'REFN', - 'RIN', - 'CHAN', - 'NOTE', - 'SHARED_NOTE', - 'SOUR', - 'OBJE', - // non standard tags - '_NMR', - 'MARR_CIVIL', - 'MARR_RELIGIOUS', - 'MARR_PARTNERS', - 'MARR_UNKNOWN', - '_COML', - '_MBON', - '_MARI', - '_SEPR', - '_TODO', - ]; - break; - - case Source::RECORD_TYPE: - $tags = [ - // Facts for sources - 'DATA', - 'AUTH', - 'TITL', - 'ABBR', - 'PUBL', - 'TEXT', - 'REPO', - 'REFN', - 'RIN', - 'CHAN', - 'NOTE', - 'SHARED_NOTE', - 'OBJE', - 'RESN', - ]; - break; - - case Repository::RECORD_TYPE: - $tags = [ - // Facts for repositories - 'NAME', - 'ADDR', - 'PHON', - 'EMAIL', - 'FAX', - 'WWW', - 'NOTE', - 'SHARED_NOTE', - 'REFN', - 'RIN', - 'CHAN', - 'RESN', - ]; - break; - - case 'PLAC': - $tags = [ - // Facts for places - 'FONE', - 'ROMN', - // non standard tags - '_GOV', - '_HEB', - ]; - break; - - case 'NAME': - $tags = [ - // Facts subordinate to NAME - 'FONE', - 'ROMN', - // non standard tags - '_HEB', - '_AKA', - '_MARNM', - ]; - break; - - default: - $tags = []; - break; - } - - $facts = []; - foreach ($tags as $tag) { - $facts[$tag] = self::getLabel($tag); - } - uasort($facts, '\Fisharebest\Webtrees\I18N::strcasecmp'); - - return $facts; - } - - /** - * Translate the value for 1 FILE/2 FORM/3 TYPE - * - * @param string $type - * - * @return string - */ - public static function getFileFormTypeValue(string $type): string - { - $element = Registry::elementFactory()->make('OBJE:FILE:FORM:TYPE'); - - return $element->values()[$type] ?? $type; - } - - /** - * A list of all possible values for 1 FILE/2 FORM/3 TYPE - * - * @return array<string> - */ - public static function getFileFormTypes(): array - { - $element = Registry::elementFactory()->make('OBJE:FILE:FORM:TYPE'); - - return array_filter($element->values()); - } - - /** - * Generate a value for a new _UID field. - * Instead of RFC4122-compatible UUIDs, generate ones that - * are compatible with PAF, Legacy, RootsMagic, etc. - * In these, the string is upper-cased, dashes are removed, - * and a two-byte checksum is added. - * - * @return string - */ - public static function createUid(): string - { - $uid = str_replace('-', '', Uuid::uuid4()->toString()); - - $checksum_a = 0; // a sum of the bytes - $checksum_b = 0; // a sum of the incremental values of $checksum_a - - // Compute checksums - for ($i = 0; $i < 32; $i += 2) { - $checksum_a += hexdec(substr($uid, $i, 2)); - $checksum_b += $checksum_a & 0xff; - } - - return strtoupper($uid . substr(dechex($checksum_a), -2) . substr(dechex($checksum_b), -2)); - } } diff --git a/app/Http/RequestHandlers/TreePreferencesPage.php b/app/Http/RequestHandlers/TreePreferencesPage.php index 5f929b0e39..520a6d6d12 100644 --- a/app/Http/RequestHandlers/TreePreferencesPage.php +++ b/app/Http/RequestHandlers/TreePreferencesPage.php @@ -22,7 +22,6 @@ namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Contracts\UserInterface; use Fisharebest\Webtrees\Date; -use Fisharebest\Webtrees\GedcomTag; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Module\ModuleThemeInterface; @@ -32,6 +31,7 @@ use Fisharebest\Webtrees\Services\TreeService; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\SurnameTradition; use Fisharebest\Webtrees\Tree; +use Illuminate\Support\Collection; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -51,6 +51,39 @@ class TreePreferencesPage implements RequestHandlerInterface { use ViewResponseTrait; + private const ALL_FAM_FACTS = [ + 'RESN', 'ANUL', 'CENS', 'DIV', 'DIVF', 'ENGA', 'MARB', 'MARC', 'MARR', 'MARL', 'MARS', 'RESI', 'EVEN', + 'NCHI', 'SUBM', 'SLGS', 'REFN', 'RIN', 'CHAN', 'NOTE', 'SHARED_NOTE', 'SOUR', 'OBJE', + '_NMR', '_COML', '_MBON', '_MARI', '_SEPR', '_TODO', + ]; + + private const ALL_INDI_FACTS = [ + 'RESN', 'NAME', 'SEX', 'BIRT', 'CHR', 'DEAT', 'BURI', 'CREM', 'ADOP', 'BAPM', 'BARM', 'BASM', + 'BLES', 'CHRA', 'CONF', 'FCOM', 'ORDN', 'NATU', 'EMIG', 'IMMI', 'CENS', 'PROB', 'WILL', + 'GRAD', 'RETI', 'EVEN', 'CAST', 'DSCR', 'EDUC', 'IDNO', 'NATI', 'NCHI', 'NMR', 'OCCU', 'PROP', + 'RELI', 'RESI', 'SSN', 'TITL', 'FACT', 'BAPL', 'CONL', 'ENDL', 'SLGC', 'SUBM', 'ASSO', + 'ALIA', 'ANCI', 'DESI', 'RFN', 'AFN', 'REFN', 'RIN', 'CHAN', 'NOTE', 'SHARED_NOTE', 'SOUR', 'OBJE', + '_BRTM', '_DEG', '_DNA', '_EYEC', '_FNRL', '_HAIR', '_HEIG', '_HNM', '_HOL', '_INTE', '_MDCL', + '_MEDC', '_MILI', '_MILT', '_NAME', '_NAMS', '_NLIV', '_NMAR', '_PRMN', '_TODO', '_UID', '_WEIG', '_YART', + ]; + + private const ALL_NAME_FACTS = [ + 'FONE', 'ROMN', '_HEB', '_AKA', '_MARNM', + ]; + + private const ALL_PLAC_FACTS = [ + 'FONE', 'ROMN', '_GOV', '_HEB', + ]; + + private const ALL_REPO_FACTS = [ + 'NAME', 'ADDR', 'PHON', 'EMAIL', 'FAX', 'WWW', 'NOTE', 'SHARED_NOTE', 'REFN', 'RIN', 'CHAN', 'RESN', + ]; + + private const ALL_SOUR_FACTS = [ + 'DATA', 'AUTH', 'TITL', 'ABBR', 'PUBL', 'TEXT', 'REPO', 'REFN', 'RIN', + 'CHAN', 'NOTE', 'SHARED_NOTE', 'OBJE', 'RESN', + ]; + /** @var ModuleService */ private $module_service; @@ -163,12 +196,41 @@ class TreePreferencesPage implements RequestHandlerInterface return Auth::isMember($tree, $user); }); - $all_fam_facts = GedcomTag::getPicklistFacts('FAM'); - $all_indi_facts = GedcomTag::getPicklistFacts('INDI'); - $all_name_facts = GedcomTag::getPicklistFacts('NAME'); - $all_plac_facts = GedcomTag::getPicklistFacts('PLAC'); - $all_repo_facts = GedcomTag::getPicklistFacts('REPO'); - $all_sour_facts = GedcomTag::getPicklistFacts('SOUR'); + $all_fam_facts = Collection::make(self::ALL_FAM_FACTS) + ->mapWithKeys(static function (string $tag): array { + return [$tag => Registry::elementFactory()->make('FAM:' . $tag)->label()]; + }) + ->sort(I18N::comparator()); + + $all_indi_facts = Collection::make(self::ALL_INDI_FACTS) + ->mapWithKeys(static function (string $tag): array { + return [$tag => Registry::elementFactory()->make('INDI:' . $tag)->label()]; + }) + ->sort(I18N::comparator()); + + $all_name_facts = Collection::make(self::ALL_NAME_FACTS) + ->mapWithKeys(static function (string $tag): array { + return [$tag => Registry::elementFactory()->make('INDI:NAME:' . $tag)->label()]; + }) + ->sort(I18N::comparator()); + + $all_plac_facts = Collection::make(self::ALL_PLAC_FACTS) + ->mapWithKeys(static function (string $tag): array { + return [$tag => Registry::elementFactory()->make('INDI:FACT:PLAC:' . $tag)->label()]; + }) + ->sort(I18N::comparator()); + + $all_repo_facts = Collection::make(self::ALL_REPO_FACTS) + ->mapWithKeys(static function (string $tag): array { + return [$tag => Registry::elementFactory()->make('SOUR:' . $tag)->label()]; + }) + ->sort(I18N::comparator()); + + $all_sour_facts = Collection::make(self::ALL_SOUR_FACTS) + ->mapWithKeys(static function (string $tag): array { + return [$tag => Registry::elementFactory()->make('SOUR:' . $tag)->label()]; + }) + ->sort(I18N::comparator()); $all_surname_traditions = SurnameTradition::allDescriptions(); diff --git a/app/Http/RequestHandlers/TreePrivacyPage.php b/app/Http/RequestHandlers/TreePrivacyPage.php index e55b735744..5790fe1aa8 100644 --- a/app/Http/RequestHandlers/TreePrivacyPage.php +++ b/app/Http/RequestHandlers/TreePrivacyPage.php @@ -124,7 +124,7 @@ class TreePrivacyPage implements RequestHandlerInterface return $row; }) ->sort(static function (stdClass $x, stdClass $y): int { - return I18N::strcasecmp($x->tag_label, $y->tag_label); + return I18N::comparator()($x->tag_label, $y->tag_label); }) ->all(); } @@ -170,7 +170,7 @@ class TreePrivacyPage implements RequestHandlerInterface } } - uasort($all_tags, '\Fisharebest\Webtrees\I18N::strcasecmp'); + uasort($all_tags, I18N::comparator()); return array_merge( ['' => I18N::translate('All facts and events')], diff --git a/app/I18N.php b/app/I18N.php index 8514a9b3f7..669ca333ae 100644 --- a/app/I18N.php +++ b/app/I18N.php @@ -19,6 +19,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees; +use Closure; use Collator; use Exception; use Fisharebest\Localization\Locale; @@ -541,22 +542,25 @@ class I18N } /** - * Perform a case-insensitive comparison of two strings. + * A closure which will compare strings using local collation rules. * - * @param string $string1 - * @param string $string2 - * - * @return int + * @return Closure */ - public static function strcasecmp(string $string1, string $string2): int + public static function comparator(): Closure { if (self::$collator instanceof Collator) { - return self::$collator->compare($string1, $string2); + return static function (string $x, string $y): int { + return (int) self::$collator->compare($x, $y); + }; } - return strcmp(self::strtolower($string1), self::strtolower($string2)); + return static function (string $x, string $y): int { + return strcmp(self::strtolower($x), self::strtolower($y)); + }; } + + /** * Convert a string to lower case. * diff --git a/app/Module/ChartsBlockModule.php b/app/Module/ChartsBlockModule.php index e9ba06c74f..aaaf2ba5bf 100644 --- a/app/Module/ChartsBlockModule.php +++ b/app/Module/ChartsBlockModule.php @@ -270,7 +270,7 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface 'hourglass' => I18N::translate('Hourglass chart'), 'treenav' => I18N::translate('Interactive tree'), ]; - uasort($charts, 'Fisharebest\Webtrees\I18N::strcasecmp'); + uasort($charts, I18N::comparator()); $individual = Registry::individualFactory()->make($xref, $tree); diff --git a/app/Module/ColorsTheme.php b/app/Module/ColorsTheme.php index 22f40bc689..fe158e45e0 100644 --- a/app/Module/ColorsTheme.php +++ b/app/Module/ColorsTheme.php @@ -183,7 +183,7 @@ class ColorsTheme extends CloudsTheme 'tealtop' => I18N::translate('Teal Top'), ]; - uasort($palettes, '\Fisharebest\Webtrees\I18N::strcasecmp'); + uasort($palettes, I18N::comparator()); return $palettes; } diff --git a/app/Module/FamilyTreeStatisticsModule.php b/app/Module/FamilyTreeStatisticsModule.php index c03482a51d..ea6d913dff 100644 --- a/app/Module/FamilyTreeStatisticsModule.php +++ b/app/Module/FamilyTreeStatisticsModule.php @@ -124,7 +124,7 @@ class FamilyTreeStatisticsModule extends AbstractModule implements ModuleBlockIn $all_surnames[$top_surname] = $variants; } - uksort($all_surnames, [I18N::class, 'strcasecmp']); + uksort($all_surnames, I18N::comparator()); //find a module providing individual lists $module = app(ModuleService::class)->findByComponent(ModuleListInterface::class, $tree, Auth::user())->first(static function (ModuleInterface $module) { diff --git a/app/Module/ModuleThemeTrait.php b/app/Module/ModuleThemeTrait.php index 4023625f03..6753633d69 100644 --- a/app/Module/ModuleThemeTrait.php +++ b/app/Module/ModuleThemeTrait.php @@ -152,7 +152,7 @@ trait ModuleThemeTrait } usort($menus, static function (Menu $x, Menu $y): int { - return I18N::strcasecmp($x->getLabel(), $y->getLabel()); + return I18N::comparator()($x->getLabel(), $y->getLabel()); }); return $menus; diff --git a/app/Module/TopSurnamesModule.php b/app/Module/TopSurnamesModule.php index 6d79b4fabb..5ecb1b1e3f 100644 --- a/app/Module/TopSurnamesModule.php +++ b/app/Module/TopSurnamesModule.php @@ -133,7 +133,7 @@ class TopSurnamesModule extends AbstractModule implements ModuleBlockInterface switch ($infoStyle) { case 'tagcloud': - uksort($all_surnames, [I18N::class, 'strcasecmp']); + uksort($all_surnames, I18N::comparator()); $content = FunctionsPrintLists::surnameTagCloud($all_surnames, $module, true, $tree); break; case 'list': diff --git a/app/Services/ModuleService.php b/app/Services/ModuleService.php index 7f780e7ef3..11f4fbdef6 100644 --- a/app/Services/ModuleService.php +++ b/app/Services/ModuleService.php @@ -515,20 +515,20 @@ class ModuleService switch ($interface) { case ModuleFooterInterface::class: - return $modules->sort($this->footerSorter()); + return $modules->sort($this->footerComparator()); case ModuleMenuInterface::class: - return $modules->sort($this->menuSorter()); + return $modules->sort($this->menuComparator()); case ModuleSidebarInterface::class: - return $modules->sort($this->sidebarSorter()); + return $modules->sort($this->sidebarComparator()); case ModuleTabInterface::class: - return $modules->sort($this->tabSorter()); + return $modules->sort($this->tabComparator()); default: if ($sort) { - return $modules->sort($this->moduleSorter()); + return $modules->sort($this->moduleComparator()); } return $modules; @@ -725,7 +725,7 @@ class ModuleService * * @return Closure */ - private function footerSorter(): Closure + private function footerComparator(): Closure { return static function (ModuleFooterInterface $x, ModuleFooterInterface $y): int { return $x->getFooterOrder() <=> $y->getFooterOrder(); @@ -737,7 +737,7 @@ class ModuleService * * @return Closure */ - private function menuSorter(): Closure + private function menuComparator(): Closure { return static function (ModuleMenuInterface $x, ModuleMenuInterface $y): int { return $x->getMenuOrder() <=> $y->getMenuOrder(); @@ -749,7 +749,7 @@ class ModuleService * * @return Closure */ - private function sidebarSorter(): Closure + private function sidebarComparator(): Closure { return static function (ModuleSidebarInterface $x, ModuleSidebarInterface $y): int { return $x->getSidebarOrder() <=> $y->getSidebarOrder(); @@ -761,7 +761,7 @@ class ModuleService * * @return Closure */ - private function tabSorter(): Closure + private function tabComparator(): Closure { return static function (ModuleTabInterface $x, ModuleTabInterface $y): int { return $x->getTabOrder() <=> $y->getTabOrder(); @@ -776,13 +776,13 @@ class ModuleService * * @return Closure */ - private function moduleSorter(): Closure + private function moduleComparator(): Closure { return static function (ModuleInterface $x, ModuleInterface $y): int { $title1 = $x instanceof ModuleLanguageInterface ? $x->locale()->endonymSortable() : $x->title(); $title2 = $y instanceof ModuleLanguageInterface ? $y->locale()->endonymSortable() : $y->title(); - return I18N::strcasecmp($title1, $title2); + return I18N::comparator()($title1, $title2); }; } diff --git a/app/Statistics/Repository/IndividualRepository.php b/app/Statistics/Repository/IndividualRepository.php index b6ba89c233..92b0313c64 100644 --- a/app/Statistics/Repository/IndividualRepository.php +++ b/app/Statistics/Repository/IndividualRepository.php @@ -558,7 +558,7 @@ class IndividualRepository implements IndividualRepositoryInterface switch ($sorting) { default: case 'alpha': - uksort($surnames, [I18N::class, 'strcasecmp']); + uksort($surnames, I18N::comparator()); break; case 'count': break; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 12e0949f4b..2457fd2f27 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -215,11 +215,6 @@ parameters: path: app/GedcomRecord.php - - message: "#^Parameter \\#1 \\$num of function dechex expects int, float\\|int given\\.$#" - count: 1 - path: app/GedcomTag.php - - - message: "#^Strict comparison using \\=\\=\\= between '\\-dev' and '' will always evaluate to false\\.$#" count: 1 path: app/Helpers/functions.php @@ -560,7 +555,7 @@ parameters: path: app/I18N.php - - message: "#^Method Fisharebest\\\\Webtrees\\\\I18N\\:\\:strcasecmp\\(\\) should return int but returns int\\|false\\.$#" + message: "#^Cannot call method compare\\(\\) on Collator\\|null\\.$#" count: 1 path: app/I18N.php diff --git a/tests/app/I18NTest.php b/tests/app/I18NTest.php index b4ab2fb1f2..cc949fc037 100644 --- a/tests/app/I18NTest.php +++ b/tests/app/I18NTest.php @@ -47,18 +47,20 @@ class I18NTest extends TestCase } /** - * @covers \Fisharebest\Webtrees\I18N::strcasecmp() + * @covers \Fisharebest\Webtrees\I18N::comparator() * * @return void */ - public function testStrcasecmp(): void + public function testComparator(): void { - self::assertSame(I18N::strcasecmp('', ''), 0); - self::assertSame(I18N::strcasecmp('Abc', 'abc'), 0); - self::assertTrue(I18N::strcasecmp('Abc', 'bcd') < 0); - self::assertTrue(I18N::strcasecmp('bcd', 'ABC') > 0); - self::assertTrue(I18N::strcasecmp('Abc', 'abcd') < 0); - self::assertTrue(I18N::strcasecmp('Abcd', 'abc') > 0); + $comparator = I18N::comparator(); + + self::assertSame($comparator('', ''), 0); + self::assertSame($comparator('Abc', 'abc'), 0); + self::assertTrue($comparator('Abc', 'bcd') < 0); + self::assertTrue($comparator('bcd', 'ABC') > 0); + self::assertTrue($comparator('Abc', 'abcd') < 0); + self::assertTrue($comparator('Abcd', 'abc') > 0); } /** |
