Passed
Push — main ( b205bb...1d3d49 )
by Mark
12:04
created

TwemojiProcessor::getTwemojiImage()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 5
nop 1
dl 0
loc 22
ccs 14
cts 14
cp 1
crap 5
rs 9.5222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Emoji\Extension\Twemoji;
6
7
use League\Configuration\ConfigurationAwareInterface;
8
use League\Configuration\ConfigurationInterface;
9
use League\Emoji\EmojiConverterInterface;
10
use League\Emoji\Event\DocumentParsedEvent;
11
use League\Emoji\Node\Emoji;
12
use League\Emoji\Node\Image;
13
use League\Emoji\Node\Node;
14
use League\Emoji\Util\HtmlElement;
15
16
/**
17
 * Replaces emojis with Twemoji images.
18
 */
19
final class TwemojiProcessor implements ConfigurationAwareInterface
20
{
21
    public const CONVERSION_TYPE = 'twemoji';
22
23
    /**
24
     * @var ConfigurationInterface
25
     *
26
     * @psalm-readonly-allow-private-mutation
27
     * @psalm-suppress PropertyNotSetInConstructor
28
     */
29
    private $config;
30
31 18
    public function __invoke(DocumentParsedEvent $e): void
32
    {
33 18
        foreach ($e->getDocument()->getNodes() as $node) {
34
            // Only convert types that are set to "twemoji".
35 18
            if (! ($node instanceof Emoji) || $node->hexcode === null || $this->getConversionType($node) !== self::CONVERSION_TYPE) {
36 18
                continue;
37
            }
38
39 18
            $twemoji = $this->getTwemojiImage($node);
40
41 18
            $node->replaceWith($twemoji);
42
        }
43 18
    }
44
45 18
    protected function addClassesToNode(Node $node, ?string ...$classes): void
46
    {
47 18
        $prefix = $this->getClassPrefix();
48
49
        $classes = \array_map(static function (string $class) use ($prefix) {
50 18
            return HtmlElement::cleanCssIdentifier($prefix . $class);
51 18
        }, \array_filter($classes));
52
53 18
        $classes = \array_unique(\array_filter(\array_merge($this->getClasses(), $classes)));
54
55 18
        $node->addClass(...$classes);
56 18
    }
57
58
    /** @return string[] */
59 18
    protected function getClasses(): array
60
    {
61
        /** @var string[] $classes */
62 18
        $classes = (array) $this->config->get('twemoji.classes');
63
64 18
        return $classes;
65
    }
66
67 18
    protected function getClassPrefix(): string
68
    {
69 18
        return (string) $this->config->get('twemoji.classPrefix');
70
    }
71
72 18
    protected function getConversionType(Emoji $emoji): ?string
73
    {
74 18
        $parsedType     = $emoji->getParsedType();
75 18
        $configPath     = 'convert.' . (EmojiConverterInterface::TYPES[$parsedType] ?? '');
76 18
        $conversionType = null;
77 18
        if ($this->config->exists($configPath)) {
78 18
            $conversionType = (string) ($this->config->get($configPath) ?? '');
79
        }
80
81 18
        return $conversionType;
82
    }
83
84 18
    protected function getImageType(): string
85
    {
86 18
        return (string) $this->config->get('twemoji.type');
87
    }
88
89
    /** @return int|float|string|null */
90 18
    protected function getSize()
91
    {
92
        /** @var int|float|string|null $size */
93 18
        $size = $this->config->get('twemoji.size');
94
95 18
        return $size;
96
    }
97
98 18
    protected function getTwemojiImage(Emoji $emoji): Image
99
    {
100 18
        $image = new Image($emoji->getParsedValue(), $emoji, $this->getUrl((string) $emoji->hexcode), $emoji->annotation, $emoji->annotation);
101
102 18
        $this->addClassesToNode($image, $emoji->annotation);
103
104
        // Ensure image isn't massive and relative to its surroundings by inlining it.
105 18
        $size = $this->getSize();
106 18
        if ($this->isInline()) {
107 15
            if ($size === null) {
108 12
                $size = '1em';
109 3
            } elseif (! \is_string($size)) {
110 3
                $size .= 'em';
111
            }
112
113 15
            $image->setAttribute('style', \sprintf('width: %s; height: %s; vertical-align: middle;', $size, $size));
114 3
        } elseif ($size !== null) {
115 3
            $image->setAttribute('height', (string) $size);
116 3
            $image->setAttribute('width', (string) $size);
117
        }
118
119 18
        return $image;
120
    }
121
122 18
    protected function getUrl(string $hexcode): string
123
    {
124 18
        return \sprintf(
125
            '%s/%s/%s.%s',
126 18
            $this->getUrlBase(),
127 18
            ($imageType = $this->getImageType()) === 'png' ? '72x72' : 'svg',
128 18
            \strtolower($hexcode),
129 18
            $imageType
130
        );
131
    }
132
133 18
    protected function getUrlBase(): string
134
    {
135 18
        return (string) $this->config->get('twemoji.urlBase');
136
    }
137
138 18
    protected function isInline(): bool
139
    {
140 18
        return (bool) $this->config->get('twemoji.inline');
141
    }
142
143 18
    public function setConfiguration(ConfigurationInterface $configuration): void
144
    {
145 18
        $this->config = $configuration;
146 18
    }
147
}
148