Completed
Push — master ( 61fe4c...92e282 )
by Daniel
24:20 queued 15s
created
lib/private/Search/SearchComposer.php 1 patch
Indentation   +304 added lines, -304 removed lines patch added patch discarded remove patch
@@ -52,308 +52,308 @@
 block discarded – undo
52 52
  * @psalm-import-type CoreUnifiedSearchProvider from ResponseDefinitions
53 53
  */
54 54
 class SearchComposer {
55
-	/**
56
-	 * @var array<string, array{appId: string, provider: IProvider}>
57
-	 */
58
-	private array $providers = [];
59
-
60
-	private array $commonFilters;
61
-	private array $customFilters = [];
62
-
63
-	private array $handlers = [];
64
-
65
-	public function __construct(
66
-		private Coordinator $bootstrapCoordinator,
67
-		private ContainerInterface $container,
68
-		private IURLGenerator $urlGenerator,
69
-		private LoggerInterface $logger,
70
-		private IAppConfig $appConfig,
71
-	) {
72
-		$this->commonFilters = [
73
-			IFilter::BUILTIN_TERM => new FilterDefinition(IFilter::BUILTIN_TERM, FilterDefinition::TYPE_STRING),
74
-			IFilter::BUILTIN_SINCE => new FilterDefinition(IFilter::BUILTIN_SINCE, FilterDefinition::TYPE_DATETIME),
75
-			IFilter::BUILTIN_UNTIL => new FilterDefinition(IFilter::BUILTIN_UNTIL, FilterDefinition::TYPE_DATETIME),
76
-			IFilter::BUILTIN_TITLE_ONLY => new FilterDefinition(IFilter::BUILTIN_TITLE_ONLY, FilterDefinition::TYPE_BOOL, false),
77
-			IFilter::BUILTIN_PERSON => new FilterDefinition(IFilter::BUILTIN_PERSON, FilterDefinition::TYPE_PERSON),
78
-			IFilter::BUILTIN_PLACES => new FilterDefinition(IFilter::BUILTIN_PLACES, FilterDefinition::TYPE_STRINGS, false),
79
-			IFilter::BUILTIN_PROVIDER => new FilterDefinition(IFilter::BUILTIN_PROVIDER, FilterDefinition::TYPE_STRING, false),
80
-		];
81
-	}
82
-
83
-	/**
84
-	 * Load all providers dynamically that were registered through `registerProvider`
85
-	 *
86
-	 * If $targetProviderId is provided, only this provider is loaded
87
-	 * If a provider can't be loaded we log it but the operation continues nevertheless
88
-	 */
89
-	private function loadLazyProviders(?string $targetProviderId = null): void {
90
-		$context = $this->bootstrapCoordinator->getRegistrationContext();
91
-		if ($context === null) {
92
-			// Too early, nothing registered yet
93
-			return;
94
-		}
95
-
96
-		$registrations = $context->getSearchProviders();
97
-		foreach ($registrations as $registration) {
98
-			try {
99
-				/** @var IProvider $provider */
100
-				$provider = $this->container->get($registration->getService());
101
-				$providerId = $provider->getId();
102
-				if ($targetProviderId !== null && $targetProviderId !== $providerId) {
103
-					continue;
104
-				}
105
-				$this->providers[$providerId] = [
106
-					'appId' => $registration->getAppId(),
107
-					'provider' => $provider,
108
-				];
109
-				$this->handlers[$providerId] = [$providerId];
110
-				if ($targetProviderId !== null) {
111
-					break;
112
-				}
113
-			} catch (ContainerExceptionInterface $e) {
114
-				// Log an continue. We can be fault tolerant here.
115
-				$this->logger->error('Could not load search provider dynamically: ' . $e->getMessage(), [
116
-					'exception' => $e,
117
-					'app' => $registration->getAppId(),
118
-				]);
119
-			}
120
-		}
121
-
122
-		$this->filterProviders();
123
-
124
-		$this->loadFilters();
125
-	}
126
-
127
-	private function loadFilters(): void {
128
-		foreach ($this->providers as $providerId => $providerData) {
129
-			$appId = $providerData['appId'];
130
-			$provider = $providerData['provider'];
131
-			if (!$provider instanceof IFilteringProvider) {
132
-				continue;
133
-			}
134
-
135
-			foreach ($provider->getCustomFilters() as $filter) {
136
-				$this->registerCustomFilter($filter, $providerId);
137
-			}
138
-			foreach ($provider->getAlternateIds() as $alternateId) {
139
-				$this->handlers[$alternateId][] = $providerId;
140
-			}
141
-			foreach ($provider->getSupportedFilters() as $filterName) {
142
-				if ($this->getFilterDefinition($filterName, $providerId) === null) {
143
-					throw new InvalidArgumentException('Invalid filter ' . $filterName);
144
-				}
145
-			}
146
-		}
147
-	}
148
-
149
-	private function registerCustomFilter(FilterDefinition $filter, string $providerId): void {
150
-		$name = $filter->name();
151
-		if (isset($this->commonFilters[$name])) {
152
-			throw new InvalidArgumentException('Filter name is already used');
153
-		}
154
-
155
-		if (isset($this->customFilters[$providerId])) {
156
-			$this->customFilters[$providerId][$name] = $filter;
157
-		} else {
158
-			$this->customFilters[$providerId] = [$name => $filter];
159
-		}
160
-	}
161
-
162
-	/**
163
-	 * Get a list of all provider IDs & Names for the consecutive calls to `search`
164
-	 * Sort the list by the order property
165
-	 *
166
-	 * @param string $route the route the user is currently at
167
-	 * @param array $routeParameters the parameters of the route the user is currently at
168
-	 *
169
-	 * @return list<CoreUnifiedSearchProvider>
170
-	 */
171
-	public function getProviders(string $route, array $routeParameters): array {
172
-		$this->loadLazyProviders();
173
-
174
-		$providers = array_map(
175
-			function (array $providerData) use ($route, $routeParameters) {
176
-				$appId = $providerData['appId'];
177
-				$provider = $providerData['provider'];
178
-				$order = $provider->getOrder($route, $routeParameters);
179
-				if ($order === null) {
180
-					return;
181
-				}
182
-				$isExternalProvider = $provider instanceof IExternalProvider ? $provider->isExternalProvider() : false;
183
-				$triggers = [$provider->getId()];
184
-				if ($provider instanceof IFilteringProvider) {
185
-					$triggers += $provider->getAlternateIds();
186
-					$filters = $provider->getSupportedFilters();
187
-				} else {
188
-					$filters = [IFilter::BUILTIN_TERM];
189
-				}
190
-
191
-				return [
192
-					'id' => $provider->getId(),
193
-					'appId' => $appId,
194
-					'name' => $provider->getName(),
195
-					'icon' => $this->fetchIcon($appId, $provider->getId()),
196
-					'order' => $order,
197
-					'isExternalProvider' => $isExternalProvider,
198
-					'triggers' => array_values($triggers),
199
-					'filters' => $this->getFiltersType($filters, $provider->getId()),
200
-					'inAppSearch' => $provider instanceof IInAppSearch,
201
-				];
202
-			},
203
-			$this->providers,
204
-		);
205
-		$providers = array_filter($providers);
206
-
207
-		// Sort providers by order and strip associative keys
208
-		usort($providers, function ($provider1, $provider2) {
209
-			return $provider1['order'] <=> $provider2['order'];
210
-		});
211
-
212
-		return $providers;
213
-	}
214
-
215
-	/**
216
-	 * Filter providers based on 'unified_search.providers_allowed' core app config array
217
-	 * Will remove providers that are not in the allowed list
218
-	 */
219
-	private function filterProviders(): void {
220
-		$allowedProviders = $this->appConfig->getValueArray('core', 'unified_search.providers_allowed');
221
-
222
-		if (empty($allowedProviders)) {
223
-			return;
224
-		}
225
-
226
-		foreach (array_keys($this->providers) as $providerId) {
227
-			if (!in_array($providerId, $allowedProviders, true)) {
228
-				unset($this->providers[$providerId]);
229
-				unset($this->handlers[$providerId]);
230
-			}
231
-		}
232
-	}
233
-
234
-	private function fetchIcon(string $appId, string $providerId): string {
235
-		$icons = [
236
-			[$providerId, $providerId . '.svg'],
237
-			[$providerId, 'app.svg'],
238
-			[$appId, $providerId . '.svg'],
239
-			[$appId, $appId . '.svg'],
240
-			[$appId, 'app.svg'],
241
-			['core', 'places/default-app-icon.svg'],
242
-		];
243
-		if ($appId === 'settings' && $providerId === 'users') {
244
-			// Conflict:
245
-			// the file /apps/settings/users.svg is already used in black version by top right user menu
246
-			// Override icon name here
247
-			$icons = [['settings', 'users-white.svg']];
248
-		}
249
-		foreach ($icons as $i => $icon) {
250
-			try {
251
-				return $this->urlGenerator->imagePath(... $icon);
252
-			} catch (RuntimeException $e) {
253
-				// Ignore error
254
-			}
255
-		}
256
-
257
-		return '';
258
-	}
259
-
260
-	/**
261
-	 * @param $filters string[]
262
-	 * @return array<string, string>
263
-	 */
264
-	private function getFiltersType(array $filters, string $providerId): array {
265
-		$filterList = [];
266
-		foreach ($filters as $filter) {
267
-			$filterList[$filter] = $this->getFilterDefinition($filter, $providerId)->type();
268
-		}
269
-
270
-		return $filterList;
271
-	}
272
-
273
-	private function getFilterDefinition(string $name, string $providerId): ?FilterDefinition {
274
-		if (isset($this->commonFilters[$name])) {
275
-			return $this->commonFilters[$name];
276
-		}
277
-		if (isset($this->customFilters[$providerId][$name])) {
278
-			return $this->customFilters[$providerId][$name];
279
-		}
280
-
281
-		return null;
282
-	}
283
-
284
-	/**
285
-	 * @param array<string, string> $parameters
286
-	 */
287
-	public function buildFilterList(string $providerId, array $parameters): FilterCollection {
288
-		$this->loadLazyProviders($providerId);
289
-
290
-		$list = [];
291
-		foreach ($parameters as $name => $value) {
292
-			$filter = $this->buildFilter($name, $value, $providerId);
293
-			if ($filter === null) {
294
-				continue;
295
-			}
296
-			$list[$name] = $filter;
297
-		}
298
-
299
-		return new FilterCollection(... $list);
300
-	}
301
-
302
-	private function buildFilter(string $name, string $value, string $providerId): ?IFilter {
303
-		$filterDefinition = $this->getFilterDefinition($name, $providerId);
304
-		if ($filterDefinition === null) {
305
-			$this->logger->debug('Unable to find {name} definition', [
306
-				'name' => $name,
307
-				'value' => $value,
308
-			]);
309
-
310
-			return null;
311
-		}
312
-
313
-		if (!$this->filterSupportedByProvider($filterDefinition, $providerId)) {
314
-			// FIXME Use dedicated exception and handle it
315
-			throw new UnsupportedFilter($name, $providerId);
316
-		}
317
-
318
-		return FilterFactory::get($filterDefinition->type(), $value);
319
-	}
320
-
321
-	private function filterSupportedByProvider(FilterDefinition $filterDefinition, string $providerId): bool {
322
-		// Non exclusive filters can be ommited by apps
323
-		if (!$filterDefinition->exclusive()) {
324
-			return true;
325
-		}
326
-
327
-		$provider = $this->providers[$providerId]['provider'];
328
-		$supportedFilters = $provider instanceof IFilteringProvider
329
-			? $provider->getSupportedFilters()
330
-			: [IFilter::BUILTIN_TERM];
331
-
332
-		return in_array($filterDefinition->name(), $supportedFilters, true);
333
-	}
334
-
335
-	/**
336
-	 * Query an individual search provider for results
337
-	 *
338
-	 * @param IUser $user
339
-	 * @param string $providerId one of the IDs received by `getProviders`
340
-	 * @param ISearchQuery $query
341
-	 *
342
-	 * @return SearchResult
343
-	 * @throws InvalidArgumentException when the $providerId does not correspond to a registered provider
344
-	 */
345
-	public function search(
346
-		IUser $user,
347
-		string $providerId,
348
-		ISearchQuery $query,
349
-	): SearchResult {
350
-		$this->loadLazyProviders($providerId);
351
-
352
-		$provider = $this->providers[$providerId]['provider'] ?? null;
353
-		if ($provider === null) {
354
-			throw new InvalidArgumentException("Provider $providerId is unknown");
355
-		}
356
-
357
-		return $provider->search($user, $query);
358
-	}
55
+    /**
56
+     * @var array<string, array{appId: string, provider: IProvider}>
57
+     */
58
+    private array $providers = [];
59
+
60
+    private array $commonFilters;
61
+    private array $customFilters = [];
62
+
63
+    private array $handlers = [];
64
+
65
+    public function __construct(
66
+        private Coordinator $bootstrapCoordinator,
67
+        private ContainerInterface $container,
68
+        private IURLGenerator $urlGenerator,
69
+        private LoggerInterface $logger,
70
+        private IAppConfig $appConfig,
71
+    ) {
72
+        $this->commonFilters = [
73
+            IFilter::BUILTIN_TERM => new FilterDefinition(IFilter::BUILTIN_TERM, FilterDefinition::TYPE_STRING),
74
+            IFilter::BUILTIN_SINCE => new FilterDefinition(IFilter::BUILTIN_SINCE, FilterDefinition::TYPE_DATETIME),
75
+            IFilter::BUILTIN_UNTIL => new FilterDefinition(IFilter::BUILTIN_UNTIL, FilterDefinition::TYPE_DATETIME),
76
+            IFilter::BUILTIN_TITLE_ONLY => new FilterDefinition(IFilter::BUILTIN_TITLE_ONLY, FilterDefinition::TYPE_BOOL, false),
77
+            IFilter::BUILTIN_PERSON => new FilterDefinition(IFilter::BUILTIN_PERSON, FilterDefinition::TYPE_PERSON),
78
+            IFilter::BUILTIN_PLACES => new FilterDefinition(IFilter::BUILTIN_PLACES, FilterDefinition::TYPE_STRINGS, false),
79
+            IFilter::BUILTIN_PROVIDER => new FilterDefinition(IFilter::BUILTIN_PROVIDER, FilterDefinition::TYPE_STRING, false),
80
+        ];
81
+    }
82
+
83
+    /**
84
+     * Load all providers dynamically that were registered through `registerProvider`
85
+     *
86
+     * If $targetProviderId is provided, only this provider is loaded
87
+     * If a provider can't be loaded we log it but the operation continues nevertheless
88
+     */
89
+    private function loadLazyProviders(?string $targetProviderId = null): void {
90
+        $context = $this->bootstrapCoordinator->getRegistrationContext();
91
+        if ($context === null) {
92
+            // Too early, nothing registered yet
93
+            return;
94
+        }
95
+
96
+        $registrations = $context->getSearchProviders();
97
+        foreach ($registrations as $registration) {
98
+            try {
99
+                /** @var IProvider $provider */
100
+                $provider = $this->container->get($registration->getService());
101
+                $providerId = $provider->getId();
102
+                if ($targetProviderId !== null && $targetProviderId !== $providerId) {
103
+                    continue;
104
+                }
105
+                $this->providers[$providerId] = [
106
+                    'appId' => $registration->getAppId(),
107
+                    'provider' => $provider,
108
+                ];
109
+                $this->handlers[$providerId] = [$providerId];
110
+                if ($targetProviderId !== null) {
111
+                    break;
112
+                }
113
+            } catch (ContainerExceptionInterface $e) {
114
+                // Log an continue. We can be fault tolerant here.
115
+                $this->logger->error('Could not load search provider dynamically: ' . $e->getMessage(), [
116
+                    'exception' => $e,
117
+                    'app' => $registration->getAppId(),
118
+                ]);
119
+            }
120
+        }
121
+
122
+        $this->filterProviders();
123
+
124
+        $this->loadFilters();
125
+    }
126
+
127
+    private function loadFilters(): void {
128
+        foreach ($this->providers as $providerId => $providerData) {
129
+            $appId = $providerData['appId'];
130
+            $provider = $providerData['provider'];
131
+            if (!$provider instanceof IFilteringProvider) {
132
+                continue;
133
+            }
134
+
135
+            foreach ($provider->getCustomFilters() as $filter) {
136
+                $this->registerCustomFilter($filter, $providerId);
137
+            }
138
+            foreach ($provider->getAlternateIds() as $alternateId) {
139
+                $this->handlers[$alternateId][] = $providerId;
140
+            }
141
+            foreach ($provider->getSupportedFilters() as $filterName) {
142
+                if ($this->getFilterDefinition($filterName, $providerId) === null) {
143
+                    throw new InvalidArgumentException('Invalid filter ' . $filterName);
144
+                }
145
+            }
146
+        }
147
+    }
148
+
149
+    private function registerCustomFilter(FilterDefinition $filter, string $providerId): void {
150
+        $name = $filter->name();
151
+        if (isset($this->commonFilters[$name])) {
152
+            throw new InvalidArgumentException('Filter name is already used');
153
+        }
154
+
155
+        if (isset($this->customFilters[$providerId])) {
156
+            $this->customFilters[$providerId][$name] = $filter;
157
+        } else {
158
+            $this->customFilters[$providerId] = [$name => $filter];
159
+        }
160
+    }
161
+
162
+    /**
163
+     * Get a list of all provider IDs & Names for the consecutive calls to `search`
164
+     * Sort the list by the order property
165
+     *
166
+     * @param string $route the route the user is currently at
167
+     * @param array $routeParameters the parameters of the route the user is currently at
168
+     *
169
+     * @return list<CoreUnifiedSearchProvider>
170
+     */
171
+    public function getProviders(string $route, array $routeParameters): array {
172
+        $this->loadLazyProviders();
173
+
174
+        $providers = array_map(
175
+            function (array $providerData) use ($route, $routeParameters) {
176
+                $appId = $providerData['appId'];
177
+                $provider = $providerData['provider'];
178
+                $order = $provider->getOrder($route, $routeParameters);
179
+                if ($order === null) {
180
+                    return;
181
+                }
182
+                $isExternalProvider = $provider instanceof IExternalProvider ? $provider->isExternalProvider() : false;
183
+                $triggers = [$provider->getId()];
184
+                if ($provider instanceof IFilteringProvider) {
185
+                    $triggers += $provider->getAlternateIds();
186
+                    $filters = $provider->getSupportedFilters();
187
+                } else {
188
+                    $filters = [IFilter::BUILTIN_TERM];
189
+                }
190
+
191
+                return [
192
+                    'id' => $provider->getId(),
193
+                    'appId' => $appId,
194
+                    'name' => $provider->getName(),
195
+                    'icon' => $this->fetchIcon($appId, $provider->getId()),
196
+                    'order' => $order,
197
+                    'isExternalProvider' => $isExternalProvider,
198
+                    'triggers' => array_values($triggers),
199
+                    'filters' => $this->getFiltersType($filters, $provider->getId()),
200
+                    'inAppSearch' => $provider instanceof IInAppSearch,
201
+                ];
202
+            },
203
+            $this->providers,
204
+        );
205
+        $providers = array_filter($providers);
206
+
207
+        // Sort providers by order and strip associative keys
208
+        usort($providers, function ($provider1, $provider2) {
209
+            return $provider1['order'] <=> $provider2['order'];
210
+        });
211
+
212
+        return $providers;
213
+    }
214
+
215
+    /**
216
+     * Filter providers based on 'unified_search.providers_allowed' core app config array
217
+     * Will remove providers that are not in the allowed list
218
+     */
219
+    private function filterProviders(): void {
220
+        $allowedProviders = $this->appConfig->getValueArray('core', 'unified_search.providers_allowed');
221
+
222
+        if (empty($allowedProviders)) {
223
+            return;
224
+        }
225
+
226
+        foreach (array_keys($this->providers) as $providerId) {
227
+            if (!in_array($providerId, $allowedProviders, true)) {
228
+                unset($this->providers[$providerId]);
229
+                unset($this->handlers[$providerId]);
230
+            }
231
+        }
232
+    }
233
+
234
+    private function fetchIcon(string $appId, string $providerId): string {
235
+        $icons = [
236
+            [$providerId, $providerId . '.svg'],
237
+            [$providerId, 'app.svg'],
238
+            [$appId, $providerId . '.svg'],
239
+            [$appId, $appId . '.svg'],
240
+            [$appId, 'app.svg'],
241
+            ['core', 'places/default-app-icon.svg'],
242
+        ];
243
+        if ($appId === 'settings' && $providerId === 'users') {
244
+            // Conflict:
245
+            // the file /apps/settings/users.svg is already used in black version by top right user menu
246
+            // Override icon name here
247
+            $icons = [['settings', 'users-white.svg']];
248
+        }
249
+        foreach ($icons as $i => $icon) {
250
+            try {
251
+                return $this->urlGenerator->imagePath(... $icon);
252
+            } catch (RuntimeException $e) {
253
+                // Ignore error
254
+            }
255
+        }
256
+
257
+        return '';
258
+    }
259
+
260
+    /**
261
+     * @param $filters string[]
262
+     * @return array<string, string>
263
+     */
264
+    private function getFiltersType(array $filters, string $providerId): array {
265
+        $filterList = [];
266
+        foreach ($filters as $filter) {
267
+            $filterList[$filter] = $this->getFilterDefinition($filter, $providerId)->type();
268
+        }
269
+
270
+        return $filterList;
271
+    }
272
+
273
+    private function getFilterDefinition(string $name, string $providerId): ?FilterDefinition {
274
+        if (isset($this->commonFilters[$name])) {
275
+            return $this->commonFilters[$name];
276
+        }
277
+        if (isset($this->customFilters[$providerId][$name])) {
278
+            return $this->customFilters[$providerId][$name];
279
+        }
280
+
281
+        return null;
282
+    }
283
+
284
+    /**
285
+     * @param array<string, string> $parameters
286
+     */
287
+    public function buildFilterList(string $providerId, array $parameters): FilterCollection {
288
+        $this->loadLazyProviders($providerId);
289
+
290
+        $list = [];
291
+        foreach ($parameters as $name => $value) {
292
+            $filter = $this->buildFilter($name, $value, $providerId);
293
+            if ($filter === null) {
294
+                continue;
295
+            }
296
+            $list[$name] = $filter;
297
+        }
298
+
299
+        return new FilterCollection(... $list);
300
+    }
301
+
302
+    private function buildFilter(string $name, string $value, string $providerId): ?IFilter {
303
+        $filterDefinition = $this->getFilterDefinition($name, $providerId);
304
+        if ($filterDefinition === null) {
305
+            $this->logger->debug('Unable to find {name} definition', [
306
+                'name' => $name,
307
+                'value' => $value,
308
+            ]);
309
+
310
+            return null;
311
+        }
312
+
313
+        if (!$this->filterSupportedByProvider($filterDefinition, $providerId)) {
314
+            // FIXME Use dedicated exception and handle it
315
+            throw new UnsupportedFilter($name, $providerId);
316
+        }
317
+
318
+        return FilterFactory::get($filterDefinition->type(), $value);
319
+    }
320
+
321
+    private function filterSupportedByProvider(FilterDefinition $filterDefinition, string $providerId): bool {
322
+        // Non exclusive filters can be ommited by apps
323
+        if (!$filterDefinition->exclusive()) {
324
+            return true;
325
+        }
326
+
327
+        $provider = $this->providers[$providerId]['provider'];
328
+        $supportedFilters = $provider instanceof IFilteringProvider
329
+            ? $provider->getSupportedFilters()
330
+            : [IFilter::BUILTIN_TERM];
331
+
332
+        return in_array($filterDefinition->name(), $supportedFilters, true);
333
+    }
334
+
335
+    /**
336
+     * Query an individual search provider for results
337
+     *
338
+     * @param IUser $user
339
+     * @param string $providerId one of the IDs received by `getProviders`
340
+     * @param ISearchQuery $query
341
+     *
342
+     * @return SearchResult
343
+     * @throws InvalidArgumentException when the $providerId does not correspond to a registered provider
344
+     */
345
+    public function search(
346
+        IUser $user,
347
+        string $providerId,
348
+        ISearchQuery $query,
349
+    ): SearchResult {
350
+        $this->loadLazyProviders($providerId);
351
+
352
+        $provider = $this->providers[$providerId]['provider'] ?? null;
353
+        if ($provider === null) {
354
+            throw new InvalidArgumentException("Provider $providerId is unknown");
355
+        }
356
+
357
+        return $provider->search($user, $query);
358
+    }
359 359
 }
Please login to merge, or discard this patch.
lib/public/Search/IExternalProvider.php 1 patch
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -13,13 +13,13 @@
 block discarded – undo
13 13
  * @since 32.0.0
14 14
  */
15 15
 interface IExternalProvider extends IProvider {
16
-	/**
17
-	 * Indicates whether this search provider queries external (3rd-party) resources.
18
-	 * This is used by the Unified Search modal filter (toggle switch). By default, searching through external providers is disabled.
19
-	 *
20
-	 * @return bool default false
21
-	 *
22
-	 * @since 32.0.0
23
-	 */
24
-	public function isExternalProvider(): bool;
16
+    /**
17
+     * Indicates whether this search provider queries external (3rd-party) resources.
18
+     * This is used by the Unified Search modal filter (toggle switch). By default, searching through external providers is disabled.
19
+     *
20
+     * @return bool default false
21
+     *
22
+     * @since 32.0.0
23
+     */
24
+    public function isExternalProvider(): bool;
25 25
 }
Please login to merge, or discard this patch.