IconCollection.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <?php
  2. namespace Tools\View\Icon;
  3. use Cake\Core\InstanceConfigTrait;
  4. use Cake\Utility\Inflector;
  5. use RuntimeException;
  6. class IconCollection {
  7. use InstanceConfigTrait;
  8. /**
  9. * @var array<string, mixed>
  10. */
  11. protected $_defaultConfig = [];
  12. /**
  13. * @var string
  14. */
  15. protected $defaultSet;
  16. /**
  17. * @var array<string, \Tools\View\Icon\IconInterface>
  18. */
  19. protected $iconSets = [];
  20. /**
  21. * @param array<string, mixed> $config
  22. */
  23. public function __construct(array $config = []) {
  24. /** @var array<class-string<\Tools\View\Icon\IconInterface>|array<string, mixed>> $sets */
  25. $sets = $config['sets'] ?? [];
  26. unset($config['sets']);
  27. foreach ($sets as $set => $setConfig) {
  28. if (is_string($setConfig)) {
  29. $setConfig = [
  30. 'class' => $setConfig,
  31. ];
  32. } else {
  33. if (empty($setConfig['class'])) {
  34. throw new RuntimeException('You must define a `class` for each icon set.');
  35. }
  36. }
  37. /** @var class-string<\Tools\View\Icon\IconInterface> $className */
  38. $className = $setConfig['class'];
  39. $setConfig += $config;
  40. $this->iconSets[$set] = new $className($setConfig);
  41. }
  42. $key = array_key_first($sets);
  43. if (!$key) {
  44. throw new RuntimeException('No set defined for icon collection, at least one is required.');
  45. }
  46. $this->defaultSet = $key;
  47. $this->setConfig($config);
  48. }
  49. /**
  50. * @return array<string, array<string>>
  51. */
  52. public function names(): array {
  53. $names = [];
  54. foreach ($this->iconSets as $name => $set) {
  55. $path = $this->_config['config'][$name]['path'] ?? null;
  56. if ($path === null) {
  57. continue;
  58. }
  59. if (!file_exists($path)) {
  60. throw new RuntimeException('Cannot find file path `' . $path . '` for icon set `' . $name . '`');
  61. }
  62. $iconNames = $set->names($path);
  63. $names[$name] = $iconNames;
  64. }
  65. ksort($names);
  66. return $names;
  67. }
  68. /**
  69. * Icons using the default namespace or an already prefixed one.
  70. *
  71. * @param string $icon Icon name, prefixed for non default namespace
  72. * @param array<string, mixed> $options :
  73. * - translate, title, ...
  74. * @param array<string, mixed> $attributes :
  75. * - class, ...
  76. * @return string
  77. */
  78. public function render(string $icon, array $options = [], array $attributes = []): string {
  79. if (isset($this->_config['map'][$icon])) {
  80. $icon = $this->_config['map'][$icon];
  81. }
  82. $separator = $this->_config['separator'];
  83. $separatorPos = strpos($icon, $separator);
  84. if ($separatorPos !== false) {
  85. [$set, $icon] = explode($separator, $icon, 2);
  86. } else {
  87. $set = $this->defaultSet;
  88. }
  89. if (!isset($this->iconSets[$set])) {
  90. throw new RuntimeException('No such icon namespace: `' . $set . '`.');
  91. }
  92. $options += $this->_config;
  93. if (!isset($options['title']) || $options['title'] !== false) {
  94. $titleField = !isset($options['title']) || $options['title'] === true ? 'title' : $options['title'];
  95. if (!isset($attributes[$titleField])) {
  96. $attributes[$titleField] = ucwords(Inflector::humanize(Inflector::underscore($icon)));
  97. }
  98. }
  99. if (!isset($options['translate']) || $options['translate'] !== false) {
  100. $attributes['title'] = __($attributes['title']);
  101. }
  102. return $this->iconSets[$set]->render($icon, $options, $attributes);
  103. }
  104. }