Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
41 / 41 |
|
100.00% |
10 / 10 |
CRAP | |
100.00% |
1 / 1 |
GlobalCustomFilter | |
100.00% |
41 / 41 |
|
100.00% |
10 / 10 |
23 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setRequiredPlugins | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setFallbackFilter | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setMustFollowFilters | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setDenyList | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setApplyToAnalyzers | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getApplyToAnalyzers | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
pluginsAvailable | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
enableGlobalCustomFilters | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
7 | |||
insertGlobalCustomFilter | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace CirrusSearch\Maintenance; |
4 | |
5 | class GlobalCustomFilter { |
6 | /** @var string filter type, probably 'filter' or 'char_filter'; 'filter' by default */ |
7 | private $type; |
8 | |
9 | /** @var string[] plugins that must be present to use the filter */ |
10 | private $requiredPlugins = []; |
11 | |
12 | /** @var string local filter to use instead if requiredPlugins are not available */ |
13 | private $fallbackFilter = ''; |
14 | |
15 | /** @var string[] filters this one must come after. see T268730 */ |
16 | private $mustFollowFilters = []; |
17 | |
18 | /** @var string[] languages where this filter should not be used, by language codes */ |
19 | private $denyList = []; |
20 | |
21 | /** @var string[] which analyzers to apply to; 'text' and 'text_search' by default */ |
22 | private $applyToAnalyzers = [ 'text', 'text_search' ]; |
23 | |
24 | public function __construct( string $type = 'filter' ) { |
25 | $this->type = $type; |
26 | } |
27 | |
28 | /** |
29 | * @param string[] $requiredPlugins |
30 | * @return self |
31 | */ |
32 | public function setRequiredPlugins( array $requiredPlugins ): self { |
33 | $this->requiredPlugins = $requiredPlugins; |
34 | return $this; |
35 | } |
36 | |
37 | /** |
38 | * @param string $fallbackFilter |
39 | * @return self |
40 | */ |
41 | public function setFallbackFilter( string $fallbackFilter ): self { |
42 | $this->fallbackFilter = $fallbackFilter; |
43 | return $this; |
44 | } |
45 | |
46 | /** |
47 | * @param string[] $mustFollowFilters |
48 | * @return self |
49 | */ |
50 | public function setMustFollowFilters( array $mustFollowFilters ): self { |
51 | $this->mustFollowFilters = $mustFollowFilters; |
52 | return $this; |
53 | } |
54 | |
55 | /** |
56 | * @param string[] $denyList |
57 | * @return self |
58 | */ |
59 | public function setDenyList( array $denyList ): self { |
60 | $this->denyList = $denyList; |
61 | return $this; |
62 | } |
63 | |
64 | /** |
65 | * @param string[] $applyToAnalyzers |
66 | * @return self |
67 | */ |
68 | public function setApplyToAnalyzers( array $applyToAnalyzers ): self { |
69 | $this->applyToAnalyzers = $applyToAnalyzers; |
70 | return $this; |
71 | } |
72 | |
73 | public function getApplyToAnalyzers() { |
74 | return $this->applyToAnalyzers; |
75 | } |
76 | |
77 | /** |
78 | * check to see if the filter is compatible with the set of installed plugins |
79 | * |
80 | * @param string[] $installedPlugins |
81 | * @return bool |
82 | */ |
83 | public function pluginsAvailable( array $installedPlugins ): bool { |
84 | foreach ( $this->requiredPlugins as $reqPlugin ) { |
85 | if ( !in_array( $reqPlugin, $installedPlugins ) ) { |
86 | return false; |
87 | } |
88 | } |
89 | return true; |
90 | } |
91 | |
92 | /** |
93 | * update languages with global custom filters (e.g., homoglyph & nnbsp filters) |
94 | * |
95 | * @param mixed[] $config |
96 | * @param string $language |
97 | * @param GlobalCustomFilter[] $customFilters list of filters and info |
98 | * @param string[] $installedPlugins |
99 | * @return mixed[] updated config |
100 | */ |
101 | public static function enableGlobalCustomFilters( array $config, string $language, |
102 | array $customFilters, array $installedPlugins ) { |
103 | foreach ( $customFilters as $gcf => $gcfInfo ) { |
104 | $filterName = $gcf; |
105 | |
106 | if ( !in_array( $language, $gcfInfo->denyList ) ) { |
107 | $filterIsUsable = $gcfInfo->pluginsAvailable( $installedPlugins ); |
108 | |
109 | if ( !$filterIsUsable && $gcfInfo->fallbackFilter ) { |
110 | $filterName = $gcfInfo->fallbackFilter; |
111 | $filterIsUsable = true; |
112 | } |
113 | |
114 | if ( $filterIsUsable ) { |
115 | foreach ( $gcfInfo->getApplyToAnalyzers() as $analyzer ) { |
116 | $config = $gcfInfo->insertGlobalCustomFilter( $config, $analyzer, |
117 | $filterName, $gcfInfo ); |
118 | } |
119 | } |
120 | } |
121 | } |
122 | |
123 | return $config; |
124 | } |
125 | |
126 | /** |
127 | * insert one of the global custom filters into the right spot in the analysis chain |
128 | * @param mixed[] $config the analysis config we are modifying |
129 | * @param string $analyzer the specifc analyzer we are modifying |
130 | * @param string $filterName filter to add |
131 | * @param GlobalCustomFilter $filterInfo includes filter type & incompatible filters |
132 | * @return mixed[] updated config |
133 | */ |
134 | public static function insertGlobalCustomFilter( array $config, string $analyzer, |
135 | string $filterName, GlobalCustomFilter $filterInfo ) { |
136 | if ( !array_key_exists( $analyzer, $config['analyzer'] ) ) { |
137 | return $config; |
138 | } |
139 | |
140 | if ( $config['analyzer'][$analyzer]['type'] == 'custom' ) { |
141 | $filters = $config['analyzer'][$analyzer][$filterInfo->type] ?? []; |
142 | |
143 | $lastMustFollow = -1; |
144 | foreach ( $filterInfo->mustFollowFilters as $mustFollow ) { |
145 | $mustFollowIdx = array_keys( $filters, $mustFollow ); |
146 | $mustFollowIdx = end( $mustFollowIdx ); |
147 | if ( $mustFollowIdx !== false && $mustFollowIdx > $lastMustFollow ) { |
148 | $lastMustFollow = $mustFollowIdx; |
149 | } |
150 | } |
151 | array_splice( $filters, $lastMustFollow + 1, 0, $filterName ); |
152 | |
153 | $config['analyzer'][$analyzer][$filterInfo->type] = $filters; |
154 | } |
155 | return $config; |
156 | } |
157 | |
158 | } |