@@ -16,22 +16,20 @@ class OpenSRS extends Adapter
1616 * Instantiate a new adapter.
1717 *
1818 * @param string $apiKey
19- * @param string $apiSecret
2019 * @param string $username
2120 * @param string $password
2221 * @param array $defaultNameservers
2322 * @param bool $production
2423 * @return void
2524 */
26- public function __construct (string $ apiKey , string $ apiSecret , string $ username , string $ password , array $ defaultNameservers , bool $ production = false )
25+ public function __construct (string $ apiKey , string $ username , string $ password , array $ defaultNameservers , bool $ production = false )
2726 {
2827 $ this ->endpoint =
2928 $ production === false
3029 ? 'https://horizon.opensrs.net:55443 '
3130 : 'https://rr-n1-tor.opensrs.net:55443 ' ;
3231
3332 $ this ->apiKey = $ apiKey ;
34- $ this ->apiSecret = $ apiSecret ;
3533 $ this ->defaultNameservers = $ defaultNameservers ;
3634
3735 $ this ->user = [
@@ -41,7 +39,7 @@ public function __construct(string $apiKey, string $apiSecret, string $username,
4139
4240 $ this ->headers = [
4341 'Content-Type:text/xml ' ,
44- 'X-Username: ' . $ this -> apiSecret ,
42+ 'X-Username: ' . $ username ,
4543 ];
4644 }
4745
@@ -227,23 +225,82 @@ public function cancelPurchase(): bool
227225 return $ successful ;
228226 }
229227
230- public function suggest (array |string $ query , array $ tlds = [], $ minLength = 1 , $ maxLength = 100 ): array
228+ /**
229+ * Suggest domain names based on search query
230+ *
231+ * @param array|string $query Search terms to generate suggestions from
232+ * @param array $tlds Top-level domains to search within (e.g., ['com', 'net', 'org'])
233+ * @param int|null $limit Maximum number of results to return
234+ * @param int|null $priceMax Maximum price for premium domains
235+ * @param int|null $priceMin Minimum price for premium domains
236+ * @return array Domains with metadata: `available` (bool), `price` (float|null), `type` (string)
237+ */
238+ public function suggest (array |string $ query , array $ tlds = [], int |null $ limit = null , int |null $ priceMax = null , int |null $ priceMin = null ): array
231239 {
232240 $ query = is_array ($ query ) ? $ query : [$ query ];
233241
242+ // Determine which services to use based on parameters
243+ $ hasPriceFilter = $ priceMax !== null || $ priceMin !== null ;
244+
245+ if ($ hasPriceFilter ) {
246+ $ services = ['premium ' ];
247+ } elseif ($ limit ) {
248+ $ services = ['lookup ' , 'suggestion ' ];
249+ } else {
250+ $ services = ['suggestion ' , 'premium ' , 'lookup ' ];
251+ }
252+
234253 $ message = [
235254 'object ' => 'DOMAIN ' ,
236255 'action ' => 'name_suggest ' ,
237256 'attributes ' => [
238- 'services ' => [
239- 'suggestion ' ,
240- ],
257+ 'services ' => $ services ,
241258 'searchstring ' => implode (' ' , $ query ),
242- 'tlds ' => $ tlds ,
259+ 'skip_registry_lookup ' => 1 ,
243260 ],
244261 ];
245262
246- $ xpath = implode ('/ ' , [
263+ if (!empty ($ tlds )) {
264+ $ message ['attributes ' ]['tlds ' ] = $ tlds ;
265+ }
266+
267+ if ($ limit || $ hasPriceFilter ) {
268+ $ formattedTlds = !empty ($ tlds ) ? array_map (fn ($ tld ) => '. ' . ltrim ($ tld , '. ' ), $ tlds ) : [];
269+
270+ if ($ hasPriceFilter ) {
271+ $ message ['attributes ' ]['service_override ' ]['premium ' ] = [];
272+
273+ if (!empty ($ formattedTlds )) {
274+ $ message ['attributes ' ]['service_override ' ]['premium ' ]['tlds ' ] = $ formattedTlds ;
275+ }
276+
277+ if ($ limit ) {
278+ $ message ['attributes ' ]['service_override ' ]['premium ' ]['maximum ' ] = $ limit ;
279+ }
280+
281+ if ($ priceMin !== null ) {
282+ $ message ['attributes ' ]['service_override ' ]['premium ' ]['price_min ' ] = $ priceMin ;
283+ }
284+
285+ if ($ priceMax !== null ) {
286+ $ message ['attributes ' ]['service_override ' ]['premium ' ]['price_max ' ] = $ priceMax ;
287+ }
288+ } elseif ($ limit ) {
289+ $ message ['attributes ' ]['service_override ' ]['suggestion ' ]['maximum ' ] = $ limit ;
290+
291+ if (!empty ($ formattedTlds )) {
292+ $ message ['attributes ' ]['service_override ' ]['suggestion ' ]['tlds ' ] = $ formattedTlds ;
293+ $ message ['attributes ' ]['service_override ' ]['lookup ' ]['tlds ' ] = $ formattedTlds ;
294+ }
295+ }
296+ }
297+
298+ $ result = $ this ->send ($ message );
299+ $ result = $ this ->sanitizeResponse ($ result );
300+
301+ $ items = [];
302+
303+ $ suggestionXpath = implode ('/ ' , [
247304 '//body ' ,
248305 'data_block ' ,
249306 'dt_assoc ' ,
@@ -255,19 +312,67 @@ public function suggest(array|string $query, array $tlds = [], $minLength = 1, $
255312 'dt_array ' ,
256313 'item ' ,
257314 ]);
315+ $ suggestionElements = $ result ->xpath ($ suggestionXpath );
316+ foreach ($ suggestionElements as $ element ) {
317+ $ domainNode = $ element ->xpath ('dt_assoc/item[@key="domain"] ' );
318+ $ statusNode = $ element ->xpath ('dt_assoc/item[@key="status"] | dt_assoc/item[@key="availability"] ' );
319+ $ domain = isset ($ domainNode [0 ]) ? (string ) $ domainNode [0 ] : null ;
320+ $ status = isset ($ statusNode [0 ]) ? strtolower ((string ) $ statusNode [0 ]) : '' ;
321+ if ($ domain ) {
322+ $ items [$ domain ] = [
323+ 'available ' => in_array ($ status , ['available ' , 'true ' , '1 ' ], true ),
324+ 'price ' => null ,
325+ 'type ' => 'suggestion '
326+ ];
327+ }
328+ }
258329
259- $ result = $ this ->send ($ message );
260- $ result = $ this ->sanitizeResponse ($ result );
261- $ elements = $ result ->xpath ($ xpath );
330+ $ premiumXpath = implode ('/ ' , [
331+ '//body ' ,
332+ 'data_block ' ,
333+ 'dt_assoc ' ,
334+ 'item[@key="attributes"] ' ,
335+ 'dt_assoc ' ,
336+ 'item[@key="premium"] ' ,
337+ 'dt_assoc ' ,
338+ 'item[@key="items"] ' ,
339+ 'dt_array ' ,
340+ 'item ' ,
341+ ]);
262342
263- $ items = [] ;
343+ $ premiumElements = $ result -> xpath ( $ premiumXpath ) ;
264344
265- foreach ($ elements as $ element ) {
345+ foreach ($ premiumElements as $ element ) {
266346 $ item = $ element ->xpath ('dt_assoc/item ' );
267- $ domain = (string ) $ item [0 ];
268- $ available = (string ) $ item [1 ] === 'available ' ;
269347
270- $ items [$ domain ] = $ available ;
348+ $ domain = null ;
349+ $ available = false ;
350+ $ price = null ;
351+
352+ foreach ($ item as $ field ) {
353+ $ key = (string ) $ field ['key ' ];
354+ $ value = (string ) $ field ;
355+
356+ switch ($ key ) {
357+ case 'domain ' :
358+ $ domain = $ value ;
359+ break ;
360+ case 'status ' :
361+ $ available = $ value === 'available ' ;
362+ break ;
363+ case 'price ' :
364+ $ price = is_numeric ($ value ) ? (float ) $ value : null ;
365+ break ;
366+ }
367+ }
368+
369+ if ($ domain ) {
370+ $ items [$ domain ] = [
371+ 'available ' => $ available ,
372+ 'price ' => $ price ,
373+ 'type ' => 'premium '
374+ ];
375+ }
271376 }
272377
273378 return $ items ;
@@ -284,8 +389,8 @@ public function getDomain(string $domain): array
284389 $ message = [
285390 'object ' => 'domain ' ,
286391 'action ' => 'get ' ,
392+ 'domain ' => $ domain ,
287393 'attributes ' => [
288- 'domain ' => $ domain ,
289394 'type ' => 'all_info ' ,
290395 'clean_ca_subset ' => 1 ,
291396 ],
@@ -437,6 +542,48 @@ private function createArray(string $key, array $ary): string
437542 return implode (PHP_EOL , $ result );
438543 }
439544
545+ private function createAssoc (string $ key , array $ assoc ): string
546+ {
547+ $ result = [
548+ '<item key=" ' .$ key .'"> ' ,
549+ '<dt_assoc> ' ,
550+ ];
551+
552+ foreach ($ assoc as $ itemKey => $ itemValue ) {
553+ if (is_array ($ itemValue )) {
554+ if (array_keys ($ itemValue ) === range (0 , count ($ itemValue ) - 1 )) {
555+ $ result [] = $ this ->createArray ($ itemKey , $ itemValue );
556+ } else {
557+ $ result [] = $ this ->createAssoc ($ itemKey , $ itemValue );
558+ }
559+ } else {
560+ $ result [] = $ this ->createEnvelopItem ($ itemKey , $ itemValue );
561+ }
562+ }
563+
564+ $ result [] = '</dt_assoc> ' ;
565+ $ result [] = '</item> ' ;
566+
567+ return implode (PHP_EOL , $ result );
568+ }
569+
570+ private function createServiceOverride (array $ overrides ): string
571+ {
572+ $ result = [
573+ '<item key="service_override"> ' ,
574+ '<dt_assoc> ' ,
575+ ];
576+
577+ foreach ($ overrides as $ serviceName => $ serviceConfig ) {
578+ $ result [] = $ this ->createAssoc ($ serviceName , $ serviceConfig );
579+ }
580+
581+ $ result [] = '</dt_assoc> ' ;
582+ $ result [] = '</item> ' ;
583+
584+ return implode (PHP_EOL , $ result );
585+ }
586+
440587 private function createEnvelopItem (string $ key , string |int |array $ value ): string
441588 {
442589 if (is_array ($ value )) {
@@ -567,7 +714,7 @@ private function createNamespaceAssign(array $nameservers): string
567714 return implode (PHP_EOL , $ result );
568715 }
569716
570- private function buildEnvelop (string $ object , string $ action , array $ attributes , string $ domain = null ): string
717+ private function buildEnvelop (string $ object , string $ action , array $ attributes , ? string $ domain = null ): string
571718 {
572719 $ result = [
573720 '<?xml version="1.0" encoding="UTF-8" standalone="no"?> ' ,
@@ -604,6 +751,9 @@ private function buildEnvelop(string $object, string $action, array $attributes,
604751 case 'remove_ns ' :
605752 $ result [] = $ this ->createNamespaceAssign ($ value );
606753 break ;
754+ case 'service_override ' :
755+ $ result [] = $ this ->createServiceOverride ($ value );
756+ break ;
607757 default :
608758 $ result [] =
609759 is_array ($ value )
0 commit comments