Lines 90.24% 37 / 41
Methods 33.33% 1 / 3
Classes 0.00% 0 / 1
Covered by tests of size
Name Lines Methods CRAP
 waitForHealthy 88.23% 15 / 17 0.00% 0 / 1 8.10
 configureElasticsearch 85.71% 12 / 14 0.00% 0 / 1 4.05
 configureOpenSearch 100.00% 10 / 10 100.00% 1 / 1 1
33class SearchClientFactory
34{
35    /**
36     * Polls the search engine health endpoint until it responds with a 2xx–4xx status.
37     */
38    public static function waitForHealthy(
39        string $baseUri,
40        int $timeoutSeconds = 15,
41        ?HttpClientInterface $httpClient = null,
42        ?callable $httpClientFactory = null,
43    ): void {
44        try {
45            $http = $httpClient;
46            if ($http === null && $httpClientFactory !== null) {
47                $createdHttpClient = $httpClientFactory();
48                if ($createdHttpClient instanceof HttpClientInterface) {
49                    $http = $createdHttpClient;
50                }
51            }
52
53            $http ??= HttpClient::create(['verify_peer' => false]);
54            $deadline = time() + $timeoutSeconds;
55            do {
56                try {
57                    $res = $http->request('GET', rtrim($baseUri, characters: '/') . '/_cluster/health');
58                    $code = $res->getStatusCode();
59                    if ($code >= 200 && $code < 500) {
60                        break;
61                    }
62                } catch (Throwable $exception) {
63                    unset($exception);
64                }
65                usleep(500_000);
66            } while (time() < $deadline);
67        } catch (Throwable $exception) {
68            unset($exception);
69        }
70    }
71
72    /**
73     * Configures the Elasticsearch client and attaches it to the Configuration.
74     */
75    public static function configureElasticsearch(
76        Configuration $faqConfig,
77        string $configDir,
78        ?HttpClientInterface $httpClient = null,
79        ?callable $clientFactory = null,
80    ): void {
81        require $configDir . '/constants_elasticsearch.php';
82        $esConfig = new ElasticsearchConfiguration($configDir . '/elasticsearch.php');
83
84        $esBaseUri = $_ENV['ELASTICSEARCH_BASE_URI'] ?? $esConfig->getHosts()[0];
85
86        self::waitForHealthy($esBaseUri, (int) ($_ENV['SEARCH_WAIT_TIMEOUT'] ?? 15), $httpClient);
87
88        try {
89            $esClient = null;
90            if ($clientFactory !== null) {
91                $createdClient = $clientFactory($esBaseUri);
92                if ($createdClient instanceof Client) {
93                    $esClient = $createdClient;
94                }
95            }
96
97            $esClient ??= ClientBuilder::create()->setHosts([$esBaseUri])->build();
98            $faqConfig->setElasticsearch($esClient);
99            $faqConfig->setElasticsearchConfig($esConfig);
100        } catch (AuthenticationException $exception) {
101            unset($exception);
102        }
103    }
104
105    /**
106     * Configures the OpenSearch client and attaches it to the Configuration.
107     */
108    public static function configureOpenSearch(
109        Configuration $faqConfig,
110        string $configDir,
111        ?HttpClientInterface $httpClient = null,
112    ): void {
113        require $configDir . '/constants_opensearch.php';
114        $openSearchConfig = new OpenSearchConfiguration($configDir . '/opensearch.php');
115
116        $baseUri = $_ENV['OPENSEARCH_BASE_URI'] ?? $openSearchConfig->getHosts()[0];
117
118        self::waitForHealthy($baseUri, (int) ($_ENV['SEARCH_WAIT_TIMEOUT'] ?? 15), $httpClient);
119
120        $client = new SymfonyClientFactory()->create([
121            'base_uri' => $baseUri,
122            'verify_peer' => false,
123        ]);
124        $faqConfig->setOpenSearch($client);
125        $faqConfig->setOpenSearchConfig($openSearchConfig);
126    }
127}