@@ -27,19 +27,27 @@ final class Iconify
2727{
2828 public const API_ENDPOINT = 'https://api.iconify.design ' ;
2929
30+ // URL must be 500 chars max (iconify limit)
31+ // -39 chars: https://api.iconify.design/XXX.json?icons=
32+ // -safe margin
33+ private const int MAX_ICONS_QUERY_LENGTH = 400 ;
34+
3035 private HttpClientInterface $ http ;
3136 private \ArrayObject $ sets ;
37+ private int $ maxIconsQueryLength ;
3238
3339 public function __construct (
3440 private CacheInterface $ cache ,
3541 string $ endpoint = self ::API_ENDPOINT ,
3642 ?HttpClientInterface $ http = null ,
43+ ?int $ maxIconsQueryLength = null ,
3744 ) {
3845 if (!class_exists (HttpClient::class)) {
3946 throw new \LogicException ('You must install "symfony/http-client" to use Iconify. Try running "composer require symfony/http-client". ' );
4047 }
4148
4249 $ this ->http = ScopingHttpClient::forBaseUri ($ http ?? HttpClient::create (), $ endpoint );
50+ $ this ->maxIconsQueryLength = min (self ::MAX_ICONS_QUERY_LENGTH , $ maxIconsQueryLength ?? self ::MAX_ICONS_QUERY_LENGTH );
4351 }
4452
4553 public function metadataFor (string $ prefix ): array
@@ -95,13 +103,10 @@ public function fetchIcons(string $prefix, array $names): array
95103 sort ($ names );
96104 $ queryString = implode (', ' , $ names );
97105 if (!preg_match ('#^[a-z0-9-,]+$# ' , $ queryString )) {
98- throw new \InvalidArgumentException ('Invalid icon names. ' );
106+ throw new \InvalidArgumentException ('Invalid icon names. ' . $ queryString );
99107 }
100108
101- // URL must be 500 chars max (iconify limit)
102- // -39 chars: https://api.iconify.design/XXX.json?icons=
103- // -safe margin
104- if (450 < \strlen ($ prefix .$ queryString )) {
109+ if (self ::MAX_ICONS_QUERY_LENGTH < \strlen ($ prefix .$ queryString )) {
105110 throw new \InvalidArgumentException ('The query string is too long. ' );
106111 }
107112
@@ -155,6 +160,40 @@ public function searchIcons(string $prefix, string $query)
155160 return new \ArrayObject ($ response ->toArray ());
156161 }
157162
163+ /**
164+ * @return iterable<string[]>
165+ */
166+ public function chunk (string $ prefix , array $ names ): iterable
167+ {
168+ if (100 < ($ prefixLength = strlen ($ prefix ))) {
169+ throw new \InvalidArgumentException (sprintf ('The icon prefix "%s" is too long. ' , $ prefix ));
170+ }
171+
172+ $ maxLength = $ this ->maxIconsQueryLength - $ prefixLength ;
173+
174+ $ curBatch = [];
175+ $ curLength = 0 ;
176+ foreach ($ names as $ name ) {
177+ if (100 < ($ nameLength = strlen ($ name ))) {
178+ throw new \InvalidArgumentException (sprintf ('The icon name "%s" is too long. ' , $ name ));
179+ }
180+ if ($ curLength && ($ maxLength < ($ curLength + $ nameLength + 1 ))) {
181+ yield $ curBatch ;
182+
183+ $ curBatch = [];
184+ $ curLength = 0 ;
185+ }
186+ $ curLength += $ nameLength + 1 ;
187+ $ curBatch [] = $ name ;
188+ }
189+
190+ if ($ curLength ) {
191+ yield $ curBatch ;
192+ }
193+
194+ yield from [];
195+ }
196+
158197 private function sets (): \ArrayObject
159198 {
160199 return $ this ->sets ??= $ this ->cache ->get ('ux-iconify-sets ' , function () {
0 commit comments