Passed
Push — master ( 13879c...4f2f6e )
by Armando
08:59
created

Entity::escapeMarkdown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 6
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Longman\TelegramBot\Entities;
13
14
use Longman\TelegramBot\Entities\InlineQuery\InlineEntity;
15
use Longman\TelegramBot\Entities\InputMedia\InputMedia;
16
17
/**
18
 * Class Entity
19
 *
20
 * This is the base class for all entities.
21
 *
22
 * @link https://core.telegram.org/bots/api#available-types
23
 *
24
 * @method array  getRawData()     Get the raw data passed to this entity
25
 * @method string getBotUsername() Return the bot name passed to this entity
26
 */
27
abstract class Entity implements \JsonSerializable
28
{
29
30
31
    /**
32
     * Entity constructor.
33
     *
34
     * @todo Get rid of the $bot_username, it shouldn't be here!
35
     *
36
     * @param array  $data
37 79
     * @param string $bot_username
38
     */
39
    public function __construct(array $data, string $bot_username = '')
40 79
    {
41 11
        //Make sure we're not raw_data inception-ing
42 11
        if (array_key_exists('raw_data', $data)) {
43
            if ($data['raw_data'] === null) {
44
                unset($data['raw_data']);
45 73
            }
46
        } else {
47
            $data['raw_data'] = $data;
48 79
        }
49 79
50 79
        $data['bot_username'] = $bot_username;
51 70
        $this->assignMemberVariables($data);
52
        $this->validate();
53
    }
54
55
    /**
56
     * Return the data that should be serialized for Telegram.
57
     *
58 1
     * @return array
59
     */
60 1
    public function jsonSerialize()
61
    {
62
        return $this->getRawData();
63
    }
64
65
    /**
66
     * Perform to json
67
     *
68
     * @return string
69
     */
70
    public function toJson(): string
71
    {
72
        return json_encode($this);
73
    }
74
75
    /**
76
     * Perform to string
77
     *
78 79
     * @return string
79
     */
80 79
    public function __toString()
81 79
    {
82
        return $this->toJson();
83 79
    }
84
85
    /**
86
     * Helper to set member variables
87
     *
88
     * @param array $data
89
     */
90 49
    protected function assignMemberVariables(array $data): void
91
    {
92 49
        foreach ($data as $key => $value) {
93
            $this->$key = $value;
94
        }
95
    }
96
97
    /**
98 56
     * Get the list of the properties that are themselves Entities
99
     *
100 56
     * @return array
101
     */
102
    protected function subEntities(): array
103
    {
104
        return [];
105
    }
106
107
    /**
108
     * Perform any special entity validation
109
     */
110 73
    protected function validate(): void
111
    {
112 73
    }
113
114
    /**
115
     * Get a property from the current Entity
116
     *
117
     * @param string $property
118
     * @param mixed  $default
119
     *
120
     * @return mixed
121
     */
122
    public function getProperty(string $property, $default = null)
123 60
    {
124
        return $this->$property ?? $default;
125
    }
126 60
127
    /**
128 60
     * Return the variable for the called getter or magically set properties dynamically.
129 60
     *
130 60
     * @param $method
131
     * @param $args
132 60
     *
133
     * @return mixed|null
134 57
     */
135
    public function __call($method, $args)
136 57
    {
137 12
        //Convert method to snake_case (which is the name of the property)
138
        $property_name = mb_strtolower(ltrim(preg_replace('/[A-Z]/', '_$0', substr($method, 3)), '_'));
139 12
140 1
        $action = substr($method, 0, 3);
141
        if ($action === 'get') {
142
            $property = $this->getProperty($property_name);
143 11
144
            if ($property !== null) {
145
                //Get all sub-Entities of the current Entity
146 59
                $sub_entities = $this->subEntities();
147
148 3
                if (isset($sub_entities[$property_name])) {
149
                    $class = $sub_entities[$property_name];
150 3
151 3
                    if (is_array($class)) {
152
                        return $this->makePrettyObjectArray(reset($class), $property_name);
153 3
                    }
154
155
                    return Factory::resolveEntityClass($class, $property, $this->getProperty('bot_username'));
0 ignored issues
show
Bug introduced by
It seems like $this->getProperty('bot_username') can also be of type null; however, parameter $bot_username of Longman\TelegramBot\Enti...y::resolveEntityClass() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
                    return Factory::resolveEntityClass($class, $property, /** @scrutinizer ignore-type */ $this->getProperty('bot_username'));
Loading history...
156
                }
157 30
158
                return $property;
159
            }
160
        } elseif ($action === 'set') {
161
            // Limit setters to specific classes.
162
            if ($this instanceof InlineEntity || $this instanceof InputMedia || $this instanceof Keyboard || $this instanceof KeyboardButton) {
163
                $this->$property_name = $args[0];
164
165
                return $this;
166
            }
167
        }
168
169
        return null;
170
    }
171 1
172
    /**
173 1
     * Return an array of nice objects from an array of object arrays
174 1
     *
175
     * This method is used to generate pretty object arrays
176 1
     * mainly for PhotoSize and Entities object arrays.
177 1
     *
178 1
     * @param string $class
179
     * @param string $property_name
180
     *
181 1
     * @return array
182
     */
183
    protected function makePrettyObjectArray(string $class, string $property_name): array
184
    {
185
        $objects      = [];
186
        $bot_username = $this->getProperty('bot_username');
187
188
        $properties = array_filter($this->getProperty($property_name) ?: []);
189
        foreach ($properties as $property) {
190
            $objects[] = Factory::resolveEntityClass($class, $property, $bot_username);
0 ignored issues
show
Bug introduced by
It seems like $bot_username can also be of type null; however, parameter $bot_username of Longman\TelegramBot\Enti...y::resolveEntityClass() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

190
            $objects[] = Factory::resolveEntityClass($class, $property, /** @scrutinizer ignore-type */ $bot_username);
Loading history...
191
        }
192
193 2
        return $objects;
194
    }
195 2
196 2
    /**
197 2
     * Escape markdown (v1) special characters
198
     *
199
     * @see https://core.telegram.org/bots/api#markdown-style
200
     *
201
     * @param string $string
202
     *
203
     * @return string
204
     */
205
    public static function escapeMarkdown(string $string): string
206
    {
207
        return str_replace(
208
            ['[', '`', '*', '_',],
209
            ['\[', '\`', '\*', '\_',],
210
            $string
211 1
        );
212
    }
213 1
214 1
    /**
215 1
     * Escape markdown (v2) special characters
216
     *
217
     * @see https://core.telegram.org/bots/api#markdownv2-style
218
     *
219
     * @param string $string
220
     *
221
     * @return string
222
     */
223
    public static function escapeMarkdownV2(string $string): string
224
    {
225
        return str_replace(
226
            ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'],
227
            ['\_', '\*', '\[', '\]', '\(', '\)', '\~', '\`', '\>', '\#', '\+', '\-', '\=', '\|', '\{', '\}', '\.', '\!'],
228
            $string
229
        );
230
    }
231
232 3
    /**
233
     * Try to mention the user
234
     *
235 3
     * Mention the user with the username otherwise print first and last name
236
     * if the $escape_markdown argument is true special characters are escaped from the output
237
     *
238
     * @todo What about MarkdownV2?
239
     *
240 3
     * @param bool $escape_markdown
241 3
     *
242
     * @return string
243 3
     */
244
    public function tryMention($escape_markdown = false): string
245 3
    {
246 3
        // TryMention only makes sense for the User and Chat entity.
247 3
        if (!($this instanceof User || $this instanceof Chat)) {
248 3
            return '';
249
        }
250
251
        //Try with the username first...
252 3
        $name        = $this->getProperty('username');
253 1
        $is_username = $name !== null;
254
255
        if ($name === null) {
256 3
            //...otherwise try with the names.
257
            $name      = $this->getProperty('first_name');
258
            $last_name = $this->getProperty('last_name');
259
            if ($last_name !== null) {
260
                $name .= ' ' . $last_name;
261
            }
262
        }
263
264
        if ($escape_markdown) {
265
            $name = self::escapeMarkdown($name);
266
        }
267
268
        return ($is_username ? '@' : '') . $name;
269
    }
270
}
271