MediaWiki master
Grammar.php
Go to the documentation of this file.
1<?php
8
9use Psr\Log\LoggerInterface;
12
29class Grammar {
30
34 public function __construct(
35 protected readonly Provider $provider,
36 private readonly GrammarFallbackRegistry $postProcessor,
37 private readonly LoggerInterface $logger,
38 ) {
39 }
40
56 public function process( string $word, string $case, ?array $overrideForms = [] ): string {
57 $langCode = $this->provider->getLanguageCode();
58
59 if ( isset( $overrideForms[$langCode][$case][$word] ) ) {
60 return $overrideForms[$langCode][$case][$word];
61 }
62
63 $grammarTransformations = $this->provider->getGrammarTransformationsProvider()->getTransformations();
64
65 if ( array_key_exists( $case, $grammarTransformations ) ) {
66 $forms = $grammarTransformations[$case];
67
68 // Some names of grammar rules are aliases for other rules.
69 // In such cases the value is a string rather than object,
70 // so load the actual rules.
71 if ( is_string( $forms ) ) {
72 $alias = $forms;
73 if ( isset( $grammarTransformations[$alias] ) && is_array( $grammarTransformations[$alias] ) ) {
74 $forms = $grammarTransformations[$alias];
75 } else {
76 $this->logger->error(
77 'Expected alias {alias} to resolve to an array in grammar transformations.',
78 [ 'alias' => $alias ]
79 );
80
81 return $word;
82 }
83 }
84
85 if ( !is_array( $forms ) ) {
86 $this->logger->error(
87 'Invalid type for grammar forms. Expected array, got {type}.',
88 [ 'type' => gettype( $forms ) ]
89 );
90
91 return $word;
92 }
93
94 foreach ( $forms as $rule ) {
95 if ( !is_array( $rule ) || !isset( $rule[0] ) || !isset( $rule[1] ) ) {
96 $this->logger->warning(
97 'Skipping malformed grammar rule. Expected [pattern, replacement]. Case: {case}, Rule: {rule}',
98 [
99 'case' => $case,
100 'rule' => json_encode( $rule ),
101 ]
102 );
103 continue;
104 }
105
106 if ( !is_string( $rule[0] ) ) {
107 $this->logger->warning(
108 'Invalid grammar rule format: first element must be string. Case: {case}, Rule: {rule}',
109 [
110 'case' => $case,
111 'rule' => json_encode( $rule ),
112 ]
113 );
114 continue;
115 }
116
117 $form = $rule[0];
118
119 if ( $form === '@metadata' ) {
120 continue;
121 }
122
123 $replacement = is_string( $rule[1] ) ? $rule[1] : '';
124
125 $regex = '/' . addcslashes( $form, '/' ) . '/u';
126 $patternMatches = preg_match( $regex, $word );
127
128 if ( $patternMatches === false ) {
129 $this->logger->error(
130 'An error occurred while processing grammar: {error}. Word: {word}. Regex: /{form}/.',
131 [
132 'error' => preg_last_error_msg(),
133 'word' => $word,
134 'form' => $form,
135 ]
136 );
137 } elseif ( $patternMatches === 1 ) {
138 $word = preg_replace( $regex, $replacement, $word ) ?? $word;
139 break;
140 }
141 }
142 } else {
143 $word = $this->postProcessor->apply( $this->provider->getLanguageCode(), $word, $case );
144 }
145
146 return $word;
147 }
148}
__construct(protected readonly Provider $provider, private readonly GrammarFallbackRegistry $postProcessor, private readonly LoggerInterface $logger,)
Definition Grammar.php:34
process(string $word, string $case, ?array $overrideForms=[])
Transforms the given word into the specified grammatical case.
Definition Grammar.php:56