1<?php 2/** 3 * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved. 4 * 5 * This source code is licensed under the GPL license found in the 6 * COPYING file in the root directory of this source tree. 7 * 8 * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 9 * @author ComboStrap <support@combostrap.com> 10 * 11 */ 12 13namespace ComboStrap; 14 15require_once(__DIR__ . '/PluginUtility.php'); 16 17 18/** 19 * Class Icon 20 * @package ComboStrap 21 * @see https://combostrap.com/icon 22 * 23 * 24 * Material design does not have a repository structure where we can extract the location 25 * from the name 26 * https://material.io/resources/icons https://google.github.io/material-design-icons/ 27 * 28 * Injection via javascript to avoid problem with the php svgsimple library 29 * https://www.npmjs.com/package/svg-injector 30 */ 31class IconDownloader 32{ 33 34 const CONF_ICONS_MEDIA_NAMESPACE = "icons_namespace"; 35 const CONF_ICONS_MEDIA_NAMESPACE_DEFAULT = ":" . PluginUtility::COMBOSTRAP_NAMESPACE_NAME . ":icons"; 36 37 38 const ICON_LIBRARY_URLS = array( 39 self::ANT_DESIGN => "https://raw.githubusercontent.com/ant-design/ant-design-icons/master/packages/icons-svg/svg", 40 self::BOOTSTRAP => "https://raw.githubusercontent.com/twbs/icons/main/icons", 41 self::CARBON => "https://raw.githubusercontent.com/carbon-design-system/carbon/main/packages/icons/src/svg/32", 42 self::CLARITY => "https://raw.githubusercontent.com/vmware/clarity-assets/master/icons/essential", 43 self::CODE_ICON => "https://raw.githubusercontent.com/microsoft/vscode-codicons/main/src/icons", 44 self::ELEGANT_THEME => "https://raw.githubusercontent.com/pprince/etlinefont-bower/master/images/svg/individual_icons", 45 self::ENTYPO => "https://raw.githubusercontent.com/hypermodules/entypo/master/src/Entypo", 46 self::ENTYPO_SOCIAL => "https://raw.githubusercontent.com/hypermodules/entypo/master/src/Entypo%20Social%20Extension", 47 self::EVA => "https://raw.githubusercontent.com/akveo/eva-icons/master/package/icons", 48 self::FEATHER => "https://raw.githubusercontent.com/feathericons/feather/master/icons", 49 self::FAD => "https://raw.githubusercontent.com/fefanto/fontaudio/master/svgs", 50 self::ICONSCOUT => "https://raw.githubusercontent.com/Iconscout/unicons/master/svg/line", 51 self::LOGOS => "https://raw.githubusercontent.com/gilbarbara/logos/master/logos", 52 self::MATERIAL_DESIGN => "https://raw.githubusercontent.com/Templarian/MaterialDesign/master/svg", 53 self::OCTICON => "https://raw.githubusercontent.com/primer/octicons/main/icons", 54 self::TWEET_EMOJI => "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg", 55 self::SIMPLE_LINE => "https://raw.githubusercontent.com/thesabbir/simple-line-icons/master/src/svgs", 56 self::ICOMOON => "https://raw.githubusercontent.com/Keyamoon/IcoMoon-Free/master/SVG", 57 self::DASHICONS => "https://raw.githubusercontent.com/WordPress/dashicons/master/svg-min", 58 self::ICONOIR => "https://raw.githubusercontent.com/lucaburgio/iconoir/master/icons", 59 self::BOX_ICON => "https://raw.githubusercontent.com/atisawd/boxicons/master/svg", 60 self::LINE_AWESOME => "https://raw.githubusercontent.com/icons8/line-awesome/master/svg", 61 self::FONT_AWESOME_SOLID => "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/solid", 62 self::FONT_AWESOME_BRANDS => "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/brands", 63 self::FONT_AWESOME_REGULAR => "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/regular", 64 self::VAADIN => "https://raw.githubusercontent.com/vaadin/vaadin-icons/master/assets/svg", 65 self::CORE_UI_BRAND => "https://raw.githubusercontent.com/coreui/coreui-icons/master/svg/brand", 66 self::FLAT_COLOR_ICON => "https://raw.githubusercontent.com/icons8/flat-color-icons/master/svg", 67 self::PHOSPHOR_ICONS => "https://raw.githubusercontent.com/phosphor-icons/phosphor-icons/master/assets", 68 self::VSCODE => "https://raw.githubusercontent.com/vscode-icons/vscode-icons/master/icons", 69 self::SI_GLYPH => "https://raw.githubusercontent.com/frexy/glyph-iconset/master/svg", 70 self::AKAR_ICONS => "https://raw.githubusercontent.com/artcoholic/akar-icons/master/src/svg", 71 self::ARCTICONS => "https://raw.githubusercontent.com/Donnnno/Arcticons/main/icons/black", 72 self::HEALTH_ICONS => "https://raw.githubusercontent.com/resolvetosavelives/healthicons/main/public/icons/svg" 73 ); 74 75 const ICON_LIBRARY_WEBSITE_URLS = array( 76 self::BOOTSTRAP => "https://icons.getbootstrap.com/", 77 self::MATERIAL_DESIGN => "https://materialdesignicons.com/", 78 self::FEATHER => "https://feathericons.com/", 79 self::CODE_ICON => "https://microsoft.github.io/vscode-codicons/", 80 self::LOGOS => "https://svgporn.com/", 81 self::CARBON => "https://www.carbondesignsystem.com/guidelines/icons/library/", 82 self::TWEET_EMOJI => "https://twemoji.twitter.com/", 83 self::ANT_DESIGN => "https://ant.design/components/icon/", 84 self::CLARITY => "https://clarity.design/foundation/icons/", 85 self::OCTICON => "https://primer.style/octicons/", 86 self::ICONSCOUT => "https://iconscout.com/unicons/explore/line", 87 self::ELEGANT_THEME => "https://github.com/pprince/etlinefont-bower", 88 self::EVA => "https://akveo.github.io/eva-icons/", 89 self::ENTYPO_SOCIAL => "http://www.entypo.com", 90 self::ENTYPO => "http://www.entypo.com", 91 self::SIMPLE_LINE => "https://thesabbir.github.io/simple-line-icons", 92 self::ICOMOON => "https://icomoon.io/", 93 self::DASHICONS => "https://developer.wordpress.org/resource/dashicons/", 94 self::ICONOIR => "https://iconoir.com", 95 self::BOX_ICON => "https://boxicons.com", 96 self::LINE_AWESOME => "https://icons8.com/line-awesome", 97 self::FONT_AWESOME => "https://fontawesome.com/", 98 self::FONT_AWESOME_SOLID => "https://fontawesome.com/", 99 self::FONT_AWESOME_BRANDS => "https://fontawesome.com/", 100 self::FONT_AWESOME_REGULAR => "https://fontawesome.com/", 101 self::VAADIN => "https://vaadin.com/icons", 102 self::CORE_UI_BRAND => "https://coreui.io/icons/", 103 self::FLAT_COLOR_ICON => "https://icons8.com/icons/color", 104 self::PHOSPHOR_ICONS => "https://phosphoricons.com/", 105 self::VSCODE => "https://marketplace.visualstudio.com/items?itemName=vscode-icons-team.vscode-icons", 106 self::SI_GLYPH => "https://glyph.smarticons.co/", 107 self::AKAR_ICONS => "https://akaricons.com/", 108 self::ARCTICONS => "https://arcticons.com/", 109 self::HEALTH_ICONS => "https://healthicons.org/", 110 self::MATERIAL_DESIGN_ACRONYM => "https://materialdesignicons.com/", 111 self::COMBO => "" 112 ); 113 114 const CONF_DEFAULT_ICON_LIBRARY = "defaultIconLibrary"; 115 const CONF_DEFAULT_ICON_LIBRARY_DEFAULT = self::MATERIAL_DESIGN_ACRONYM; 116 117 /** 118 * Deprecated library acronym / name 119 */ 120 const DEPRECATED_LIBRARY_ACRONYM = array( 121 "bs" => self::BOOTSTRAP, // old one (deprecated) - the good acronym is bi (seen also in the class) 122 "md" => self::MATERIAL_DESIGN 123 ); 124 125 /** 126 * Public known acronym / name (Used in the configuration) 127 */ 128 const PUBLIC_LIBRARY_ACRONYM = array( 129 "bi" => self::BOOTSTRAP, 130 self::MATERIAL_DESIGN_ACRONYM => self::MATERIAL_DESIGN, 131 "fe" => self::FEATHER, 132 "codicon" => self::CODE_ICON, 133 "logos" => self::LOGOS, 134 "carbon" => self::CARBON, 135 "twemoji" => self::TWEET_EMOJI, 136 "ant-design" => self::ANT_DESIGN, 137 "fad" => self::FAD, 138 "clarity" => self::CLARITY, 139 "octicon" => self::OCTICON, 140 "uit" => self::ICONSCOUT, 141 "et" => self::ELEGANT_THEME, 142 "eva" => self::EVA, 143 "entypo-social" => self::ENTYPO_SOCIAL, 144 "entypo" => self::ENTYPO, 145 "simple-line-icons" => self::SIMPLE_LINE, 146 "icomoon-free" => self::ICOMOON, 147 "dashicons" => self::DASHICONS, 148 "iconoir" => self::ICONOIR, 149 "bx" => self::BOX_ICON, 150 "la" => self::LINE_AWESOME, 151 "fa-solid" => self::FONT_AWESOME_SOLID, 152 "fa-brands" => self::FONT_AWESOME_BRANDS, 153 "fa-regular" => self::FONT_AWESOME_REGULAR, 154 "vaadin" => self::VAADIN, 155 "cib" => self::CORE_UI_BRAND, 156 "flat-color-icons" => self::FLAT_COLOR_ICON, 157 "ph" => self::PHOSPHOR_ICONS, 158 "vscode-icons" => self::VSCODE, 159 "si-glyph" => self::SI_GLYPH, 160 "akar-icons" => self::AKAR_ICONS, 161 "arcticons" => self::ARCTICONS, 162 "healthicons" => self::HEALTH_ICONS, 163 "combo" => self::COMBO 164 ); 165 166 const FEATHER = "feather"; 167 const BOOTSTRAP = "bootstrap"; 168 const MATERIAL_DESIGN = "material-design"; 169 const CODE_ICON = "codicon"; 170 const LOGOS = "logos"; 171 const CARBON = "carbon"; 172 const MATERIAL_DESIGN_ACRONYM = "mdi"; 173 const TWEET_EMOJI = "twemoji"; 174 const ANT_DESIGN = "ant-design"; 175 const FAD = "fad"; 176 const CLARITY = "clarity"; 177 const OCTICON = "octicon"; 178 const ICONSCOUT = "iconscout"; 179 const ELEGANT_THEME = "elegant-theme"; 180 const EVA = "eva"; 181 const ENTYPO_SOCIAL = "entypo-social"; 182 const ENTYPO = "entypo"; 183 const SIMPLE_LINE = "simple-line"; 184 const ICOMOON = "icomoon"; 185 const DASHICONS = " dashicons"; 186 const ICONOIR = "iconoir"; 187 const BOX_ICON = "box-icon"; 188 const LINE_AWESOME = "line-awesome"; 189 const FONT_AWESOME_SOLID = "font-awesome-solid"; 190 const FONT_AWESOME_BRANDS = "font-awesome-brands"; 191 const FONT_AWESOME_REGULAR = "font-awesome-regular"; 192 const FONT_AWESOME = "font-awesome"; 193 const VAADIN = "vaadin"; 194 const CORE_UI_BRAND = "cib"; 195 const FLAT_COLOR_ICON = "flat-color-icons"; 196 const PHOSPHOR_ICONS = "ph"; 197 const VSCODE = "vscode"; 198 const SI_GLYPH = "si-glyph"; 199 const COMBO = WikiPath::COMBO_DRIVE; 200 const AKAR_ICONS = "akar-icons"; 201 const ARCTICONS = "articons"; 202 const HEALTH_ICONS = "healthicons"; 203 204 205 /** 206 * The icon library 207 * @var mixed|null 208 */ 209 private $library; 210 /** 211 * @var false|string 212 */ 213 private $iconName; 214 private WikiPath $path; 215 216 217 /** 218 * @throws ExceptionBadArgument|ExceptionFileSystem 219 */ 220 public function __construct(string $name) 221 { 222 223 $iconNameSpace = SiteConfig::getConfValue(self::CONF_ICONS_MEDIA_NAMESPACE, self::CONF_ICONS_MEDIA_NAMESPACE_DEFAULT); 224 if (substr($iconNameSpace, 0, 1) != WikiPath::NAMESPACE_SEPARATOR_DOUBLE_POINT) { 225 $iconNameSpace = WikiPath::NAMESPACE_SEPARATOR_DOUBLE_POINT . $iconNameSpace; 226 } 227 if (substr($iconNameSpace, -1) != WikiPath::NAMESPACE_SEPARATOR_DOUBLE_POINT) { 228 $iconNameSpace = $iconNameSpace . ":"; 229 } 230 $mediaPathId = $iconNameSpace . $name . ".svg";; 231 $this->path = WikiPath::createMediaPathFromPath($mediaPathId); 232 // Bug: null file created when the stream could not get any byte 233 // We delete them 234 if (FileSystems::exists($this->path)) { 235 if (FileSystems::getSize($this->path) === 0) { 236 FileSystems::delete($this->path); 237 } 238 } 239 240 /** 241 * Name parsing to extract the library name and icon name 242 */ 243 // default 244 $confValue = SiteConfig::getConfValue(self::CONF_DEFAULT_ICON_LIBRARY, self::CONF_DEFAULT_ICON_LIBRARY_DEFAULT); 245 $this->setLibrary($confValue); 246 $this->setIconName($name); 247 // parse 248 $sepPosition = strpos($name, ":"); 249 if ($sepPosition !== false) { 250 $libraryName = substr($name, 0, $sepPosition); 251 $this->setLibrary($libraryName); 252 $iconName = substr($name, $sepPosition + 1); 253 $this->setIconName($iconName); 254 255 /** 256 * Special case, internal library 257 */ 258 if ($this->getLibrary() === self::COMBO) { 259 $this->path = WikiPath::createComboResource($iconName . ".svg"); 260 } 261 } 262 263 264 } 265 266 267 public static 268 function isInIconDirectory(Path $path): bool 269 { 270 $iconNameSpace = SiteConfig::getConfValue(IconDownloader::CONF_ICONS_MEDIA_NAMESPACE, IconDownloader::CONF_ICONS_MEDIA_NAMESPACE_DEFAULT); 271 if (strpos($path->toAbsoluteId(), $iconNameSpace) !== false) { 272 return true; 273 } 274 return false; 275 } 276 277 278 /** 279 * @throws ExceptionBadArgument - if the icon library is not supported 280 * @throws ExceptionFileSystem 281 */ 282 public static function createFromName(string $name): IconDownloader 283 { 284 return new IconDownloader($name); 285 } 286 287 /** 288 * @throws ExceptionCompile 289 */ 290 private static function getPhysicalNameFromDictionary(string $logicalName, string $library) 291 { 292 293 $jsonArray = Dictionary::getFrom("$library-icons"); 294 $physicalName = $jsonArray[$logicalName]; 295 if ($physicalName === null) { 296 LogUtility::msg("The icon ($logicalName) is unknown for the library ($library)"); 297 // by default, just lowercase 298 return strtolower($logicalName); 299 } 300 return $physicalName; 301 302 } 303 304 public function getIconName(): string 305 { 306 return $this->iconName; 307 } 308 309 /** 310 * @throws ExceptionCompile 311 */ 312 public function getDownloadUrl(): string 313 { 314 315 /** 316 * The test of the supported library 317 * happens lately because the user may install them manually 318 */ 319 $library = $this->library; 320 if (!in_array($library, array_keys($this->getLibraries()))) { 321 throw new ExceptionBadArgument("The library ($library) is not a icon library supported"); 322 } 323 324 // Get the qualified library name 325 $acronymLibraries = self::getLibraries(); 326 if (isset($acronymLibraries[$library])) { 327 $library = $acronymLibraries[$library]; 328 } 329 330 // Get the url 331 $iconLibraries = self::ICON_LIBRARY_URLS; 332 if (!isset($iconLibraries[$library])) { 333 throw new ExceptionCompile("The icon library ($library) is unknown. The icon could not be downloaded.", Icon::ICON_CANONICAL_NAME); 334 } else { 335 $iconBaseUrl = $iconLibraries[$library]; 336 } 337 338 /** 339 * Name processing 340 */ 341 $iconName = $this->iconName; 342 switch ($library) { 343 344 case self::VSCODE: 345 case self::FLAT_COLOR_ICON: 346 $iconName = str_replace("-", "_", $iconName); 347 break; 348 case self::TWEET_EMOJI: 349 try { 350 $iconName = self::getEmojiCodePoint($iconName); 351 } catch (ExceptionCompile $e) { 352 throw new ExceptionCompile("The emoji name $iconName is unknown. The emoji could not be downloaded.", Icon::ICON_CANONICAL_NAME, 0, $e); 353 } 354 break; 355 case self::ANT_DESIGN: 356 // table-outlined where table is the svg, outlined the category 357 // ordered-list-outlined where ordered-list is the svg, outlined the category 358 [$iconName, $iconType] = self::explodeInTwoPartsByLastPosition($iconName, "-"); 359 $iconBaseUrl .= "/$iconType"; 360 break; 361 case self::CARBON: 362 /** 363 * Iconify normalized the name of the carbon library (making them lowercase) 364 * 365 * For instance, CSV is csv (https://icon-sets.iconify.design/carbon/csv/) 366 * 367 * This dictionary reproduce it. 368 */ 369 $iconName = self::getPhysicalNameFromDictionary($iconName, self::CARBON); 370 break; 371 case self::FAD: 372 $iconName = self::getPhysicalNameFromDictionary($iconName, self::FAD); 373 break; 374 case self::ICOMOON: 375 $iconName = self::getPhysicalNameFromDictionary($iconName, self::ICOMOON); 376 break; 377 case self::CORE_UI_BRAND: 378 $iconName = self::getPhysicalNameFromDictionary($iconName, self::CORE_UI_BRAND); 379 break; 380 case self::EVA: 381 // Eva 382 // example: eva:facebook-fill 383 [$iconName, $iconType] = self::explodeInTwoPartsByLastPosition($iconName, "-"); 384 $iconBaseUrl .= "/$iconType/svg"; 385 if ($iconType === "outline") { 386 // for whatever reason, the name of outline icon has outline at the end 387 // and not for the fill icon 388 $iconName .= "-$iconType"; 389 } 390 break; 391 case self::PHOSPHOR_ICONS: 392 // example: activity-light 393 [$iconShortName, $iconType] = self::explodeInTwoPartsByLastPosition($iconName, "-"); 394 $iconBaseUrl .= "/$iconType"; 395 break; 396 case self::SIMPLE_LINE: 397 // Bug 398 if ($iconName === "social-pinterest") { 399 $iconName = "social-pintarest"; 400 } 401 break; 402 case self::BOX_ICON: 403 [$iconType, $extractedIconName] = self::explodeInTwoPartsByLastPosition($iconName, "-"); 404 switch ($iconType) { 405 case "bxl": 406 $iconBaseUrl .= "/logos"; 407 break; 408 case "bx": 409 $iconBaseUrl .= "/regular"; 410 break; 411 case "bxs": 412 $iconBaseUrl .= "/solid"; 413 break; 414 default: 415 throw new ExceptionCompile("The box-icon icon ($iconName) has a type ($iconType) that is unknown, we can't determine the location of the icon to download"); 416 } 417 break; 418 case self::SI_GLYPH: 419 $iconName = "si-glyph-" . $iconName; 420 break; 421 case self::HEALTH_ICONS: 422 [$extractedIconName, $iconType] = self::explodeInTwoPartsByLastPosition($iconName, "-"); 423 switch ($iconType) { 424 case "outline": 425 case "negative": 426 $iconBaseUrl .= "/$iconType"; 427 $iconName = $extractedIconName; 428 break; 429 default: 430 // no 431 $iconBaseUrl .= "/filled"; 432 } 433 $iconName = self::getPhysicalNameFromDictionary($iconName, self::HEALTH_ICONS); 434 break; 435 436 } 437 438 439 // The url 440 return "$iconBaseUrl/$iconName.svg"; 441 442 } 443 444 /** 445 * @throws ExceptionCompile 446 */ 447 public function download() 448 { 449 450 451 $libraryName = $this->getLibrary(); 452 $mediaDokuPath = $this->path; 453 454 /** 455 * Create the target directory if it does not exist 456 */ 457 $iconDir = $mediaDokuPath->getParent(); 458 if (!FileSystems::exists($iconDir)) { 459 try { 460 FileSystems::createDirectory($iconDir); 461 } catch (ExceptionCompile $e) { 462 throw new ExceptionCompile("The icon directory ($iconDir) could not be created.", Icon::ICON_CANONICAL_NAME, 0, $e); 463 } 464 } 465 466 /** 467 * Download the icon 468 * The `@` delete the E_WARNING upon failure 469 * 470 * https://www.php.net/manual/en/function.fopen.php 471 */ 472 $downloadUrl = $this->getDownloadUrl(); 473 ErrorHandler::phpErrorAsException(); 474 try { 475 $filePointer = fopen($downloadUrl, 'r'); 476 } catch (\Exception $e) { 477 // (ie no icon file found at ($downloadUrl) 478 $message = "We couldn't find the <a href=\"$downloadUrl\">icon $this->iconName</a>) from the"; 479 try { 480 $urlLibrary = $this->getLibraryUrl(); 481 $message = "$message <a href=\"$urlLibrary\">library $libraryName</a>"; 482 } catch (ExceptionNotFound $e) { 483 if (PluginUtility::isDevOrTest()) { 484 throw $e; 485 } 486 $message = "$message library $libraryName"; 487 } 488 $message = "$message. Error: {$e->getMessage()}"; 489 throw new ExceptionCompile($message, Icon::ICON_CANONICAL_NAME); 490 } finally { 491 ErrorHandler::restore(); 492 } 493 494 $numberOfByte = file_put_contents($mediaDokuPath->toLocalPath()->toAbsolutePath()->toAbsoluteId(), $filePointer); 495 if ($numberOfByte !== false) { 496 LogUtility::msg("The icon ($this) from the library ($libraryName) was downloaded to ($mediaDokuPath)", LogUtility::LVL_MSG_INFO, Icon::ICON_CANONICAL_NAME); 497 } else { 498 LogUtility::msg("Internal error: The icon ($this) from the library ($libraryName) could no be written to ($mediaDokuPath)", LogUtility::LVL_MSG_ERROR, Icon::ICON_CANONICAL_NAME); 499 } 500 501 502 } 503 504 /** 505 * @param $iconName 506 * @param $mediaFilePath 507 * @deprecated Old code to download icon from the material design api 508 */ 509 public 510 static function downloadIconFromMaterialDesignApi($iconName, $mediaFilePath) 511 { 512 // Try the official API 513 // Read the icon meta of 514 // Meta Json file got all icons 515 // 516 // * Available at: https://raw.githubusercontent.com/Templarian/MaterialDesign/master/meta.json 517 // * See doc: https://github.com/Templarian/MaterialDesign-Site/blob/master/src/content/api.md) 518 $arrayFormat = true; 519 $iconMetaJson = json_decode(file_get_contents(__DIR__ . '/../resources/dictionary/icon-meta.json'), $arrayFormat); 520 $iconId = null; 521 foreach ($iconMetaJson as $key => $value) { 522 if ($value['name'] == $iconName) { 523 $iconId = $value['id']; 524 break; 525 } 526 } 527 if ($iconId != null) { 528 529 // Download 530 // Call to the API 531 // https://dev.materialdesignicons.com/contribute/site/api 532 $downloadUrl = "https://materialdesignicons.com/api/download/icon/svg/$iconId"; 533 $filePointer = file_put_contents($mediaFilePath, fopen($downloadUrl, 'r')); 534 if ($filePointer == false) { 535 LogUtility::msg("The file ($downloadUrl) could not be downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_ERROR, Icon::ICON_CANONICAL_NAME); 536 } else { 537 LogUtility::msg("The material design icon ($iconName) was downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_INFO, Icon::ICON_CANONICAL_NAME); 538 } 539 540 } 541 542 } 543 544 private static function getLibraries(): array 545 { 546 return array_merge( 547 self::PUBLIC_LIBRARY_ACRONYM, 548 self::DEPRECATED_LIBRARY_ACRONYM 549 ); 550 } 551 552 /** 553 * @throws ExceptionCompile 554 */ 555 public static function getEmojiCodePoint(string $emojiName) 556 { 557 $path = DirectoryLayout::getComboDictionaryDirectory()->resolve("emojis.json"); 558 $jsonContent = FileSystems::getContent($path); 559 $jsonArray = Json::createFromString($jsonContent)->toArray(); 560 return $jsonArray[$emojiName]; 561 } 562 563 564 /** 565 * @param string $iconName 566 * @param string $sep 567 * @return array 568 * @throws ExceptionCompile 569 */ 570 private static function explodeInTwoPartsByLastPosition(string $iconName, string $sep = "-"): array 571 { 572 $index = strrpos($iconName, $sep); 573 if ($index === false) { 574 throw new ExceptionCompile ("We expect that the icon name ($iconName) has two parts separated by a `-` (example: table-outlined). The icon could not be downloaded.", Icon::ICON_CANONICAL_NAME); 575 } 576 $firstPart = substr($iconName, 0, $index); 577 $secondPart = substr($iconName, $index + 1); 578 return [$firstPart, $secondPart]; 579 } 580 581 582 public function __toString() 583 { 584 return $this->getIconName(); 585 } 586 587 private function getLibrary() 588 { 589 return $this->library; 590 } 591 592 593 /** 594 * @noinspection PhpReturnValueOfMethodIsNeverUsedInspection 595 */ 596 private function setLibrary($libraryName): IconDownloader 597 { 598 /** 599 * The library may be not supported 600 * but the users can install them manually 601 * We test the support of the library if the logo does not exists 602 * on the file system 603 */ 604 $this->library = $libraryName; 605 return $this; 606 } 607 608 private function setIconName(string $iconName) 609 { 610 $this->iconName = $iconName; 611 } 612 613 public function getPath(): WikiPath 614 { 615 return $this->path; 616 } 617 618 /** 619 * @throws ExceptionNotFound 620 */ 621 public function getLibraryUrl() 622 { 623 $library = $this->getLibrary(); 624 $libraryUrl = @self::ICON_LIBRARY_WEBSITE_URLS[$library]; 625 if ($libraryUrl === null) { 626 throw new ExceptionNotFound("The url for the library ($library) was not found"); 627 } 628 return $libraryUrl; 629 } 630 631 632} 633