Completed
Push — master ( 95b7c3...8ed961 )
by Dan
02:21
created

MessageFactory::assembleFormattedText()   C

Complexity

Conditions 9
Paths 6

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 5.8541
c 0
b 0
f 0
cc 9
eloc 14
nc 6
nop 1
1
<?php
2
3
namespace Nopolabs\Yabot\Message;
4
5
use Nopolabs\Yabot\Helpers\SlackTrait;
6
use Nopolabs\Yabot\Slack\Client;
7
8
class MessageFactory
9
{
10
    use SlackTrait;
11
12
    public function __construct(Client $slackClient)
13
    {
14
        $this->setSlack($slackClient);
15
    }
16
17
    public function create(array $data) : Message
18
    {
19
        $formattedText = $this->assembleFormattedText($data);
20
        $user = $this->getUser($data);
21
        $channel = $this->getChannel($data);
22
23
        return new Message($this->getSlack(), $data, $formattedText, $user, $channel);
0 ignored issues
show
Bug introduced by
It seems like $channel defined by $this->getChannel($data) on line 21 can be null; however, Nopolabs\Yabot\Message\Message::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
24
    }
25
26
    public function getUser(array $data)
27
    {
28
        if (isset($data['subtype']) && $data['subtype'] === 'message_changed' && isset($data['message']['user'])) {
29
            $userId = $data['message']['user'];
30
        } else {
31
            $userId = $data['user'] ?? null;
32
        }
33
34
        return $userId ? $this->getUserById($userId) : null;
35
    }
36
37
    public function getChannel(array $data)
38
    {
39
        return $this->getChannelById($data['channel']);
40
    }
41
42
    public function assembleFormattedText(array $data) : string
43
    {
44
        if (isset($data['subtype']) && $data['subtype'] === 'message_changed' && isset($data['message']['text'])) {
45
            $formatted = [$this->formatText($data['message']['text'])];
46
        } elseif (isset($data['text'])) {
47
            $formatted = [$this->formatText($data['text'])];
48
        } else {
49
            $formatted = [];
50
        }
51
52
        if (isset($data['attachments'])) {
53
            foreach ($data['attachments'] as $attachment) {
54
                if (isset($attachment['pretext'])) {
55
                    $formatted[] = $this->formatText($attachment['pretext']);
56
                }
57
                if (isset($attachment['fallback'])) {
58
                    $formatted[] = $this->formatText($attachment['fallback']);
59
                }
60
            }
61
        }
62
63
        return trim(implode("\n", array_filter($formatted)));
64
    }
65
66
    public function formatText(string $text) : string
67
    {
68
        $pattern = '/<([^>]*)>/';
69
70
        preg_match_all($pattern, $text, $matches);
71
72
        $split = preg_split($pattern, $text);
73
74
        $index = 0;
75
        $formatted = [];
76
77
        foreach ($matches[1] as $match) {
78
            $formatted[] = $split[$index++];
79
            $formatted[] = $this->formatEntity($match);
80
        }
81
82
        if ($index < count($split)) {
83
            $formatted[] = $split[$index];
84
        }
85
86
        return trim(implode('', $formatted));
87
    }
88
89
    public function formatEntity(string $entity) : string
90
    {
91
        $pipe = strrpos($entity, '|');
92
        $readable = ($pipe !== false) ? substr($entity, $pipe + 1) : false;
93
94
        if ($entity && $entity[0] === '@') {
95
            return $this->formatUser($entity, $readable);
96
        }
97
        if ($entity && $entity[0] === '#') {
98
            return $this->formatChannel($entity, $readable);
99
        }
100
101
        return $this->formatReadable($entity, $readable);
102
    }
103
104
    public function formatUser(string $entity, $readable) : string
105
    {
106
        if ($readable) {
107
            return $readable;
108
        }
109
110
        $userId = substr($entity, 1);
111
        if ($user = $this->getUserById($userId)) {
112
            return '@'.$user->getUsername();
113
        }
114
115
        return $entity;
116
    }
117
118
    public function formatChannel(string $entity, $readable) : string
119
    {
120
        if ($readable) {
121
            return $readable;
122
        }
123
124
        $channelId = substr($entity, 1);
125
        if ($channel = $this->getChannelById($channelId)) {
126
            return '#'.$channel->getName();
127
        }
128
129
        return $entity;
130
    }
131
132
    public function formatReadable(string $match, $readable) : string
133
    {
134
        return $readable ?? $match;
135
    }
136
}
137