Passed
Push — develop ( ce83ec...1c6380 )
by
unknown
18:21 queued 16:17
created

Entity   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Test Coverage

Coverage 96.34%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 69
c 3
b 0
f 0
dl 0
loc 271
ccs 79
cts 82
cp 0.9634
rs 9.6
wmc 35

14 Methods

Rating   Name   Duplication   Size   Complexity  
A fixThumbnailRename() 0 3 2
A validate() 0 2 1
A makePrettyObjectArray() 0 11 3
B tryMention() 0 25 7
A assignMemberVariables() 0 5 2
A getProperty() 0 3 1
A __construct() 0 14 3
A escapeMarkdownV2() 0 6 1
A jsonSerialize() 0 9 1
A toJson() 0 3 1
A escapeMarkdown() 0 6 1
A subEntities() 0 3 1
B __call() 0 39 10
A __toString() 0 3 1
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
#[\AllowDynamicProperties]
28
abstract class Entity implements \JsonSerializable
29
{
30
    public static $fixThumbnailRename = true;
31
32
    /**
33
     * Entity constructor.
34
     *
35
     * @todo Get rid of the $bot_username, it shouldn't be here!
36
     *
37
     * @param array  $data
38
     * @param string $bot_username
39
     */
40 79
    public function __construct(array $data, string $bot_username = '')
41
    {
42
        //Make sure we're not raw_data inception-ing
43 79
        if (array_key_exists('raw_data', $data)) {
44 11
            if ($data['raw_data'] === null) {
45 11
                unset($data['raw_data']);
46
            }
47
        } else {
48 73
            $data['raw_data'] = $data;
49
        }
50
51 79
        $data['bot_username'] = $bot_username;
52 79
        $this->assignMemberVariables($data);
53 79
        $this->validate();
54
    }
55
56
    /**
57
     * Return the data that should be serialized for Telegram.
58
     *
59
     * @return array
60
     */
61 2
    public function jsonSerialize(): array
62
    {
63 2
        $data = get_object_vars($this);
64
65
        // Delete unnecessary data
66 2
        unset($data['raw_data']);
67 2
        unset($data['bot_username']);
68
69 2
        return $data;
70
    }
71
72
    /**
73
     * Perform to json
74
     *
75
     * @return string
76
     */
77 2
    public function toJson(): string
78
    {
79 2
        return json_encode($this);
80
    }
81
82
    /**
83
     * Perform to string
84
     *
85
     * @return string
86
     */
87
    public function __toString()
88
    {
89
        return $this->toJson();
90
    }
91
92
    /**
93
     * Helper to set member variables
94
     *
95
     * @param array $data
96
     */
97 79
    protected function assignMemberVariables(array $data): void
98
    {
99 79
        foreach ($data as $key => $value) {
100 79
            $key = $this->fixThumbnailRename($key);
101 79
            $this->$key = $value;
102
        }
103
    }
104
105
    /**
106
     * Get the list of the properties that are themselves Entities
107
     *
108
     * @return array
109
     */
110 34
    protected function subEntities(): array
111
    {
112 34
        return [];
113
    }
114
115
    /**
116
     * Perform any special entity validation
117
     */
118 55
    protected function validate(): void
119
    {
120 55
    }
121
122
    /**
123
     * Get a property from the current Entity
124
     *
125
     * @param string $property
126
     * @param mixed  $default
127
     *
128
     * @return mixed
129
     */
130 72
    public function getProperty(string $property, $default = null)
131
    {
132 72
        return $this->$property ?? $default;
133
    }
134
135
    /**
136
     * Return the variable for the called getter or magically set properties dynamically.
137
     *
138
     * @param $method
139
     * @param $args
140
     *
141
     * @return mixed|null
142
     */
143 59
    public function __call($method, $args)
144
    {
145 59
        $method = $this->fixThumbnailRename($method);
146
147
        //Convert method to snake_case (which is the name of the property)
148 59
        $property_name = mb_strtolower(ltrim(preg_replace('/[A-Z]/', '_$0', substr($method, 3)), '_'));
149 59
        $property_name = $this->fixThumbnailRename($property_name);
150
151 59
        $action = substr($method, 0, 3);
152 59
        if ($action === 'get') {
153 59
            $property = $this->getProperty($property_name);
154
155 59
            if ($property !== null) {
156
                //Get all sub-Entities of the current Entity
157 55
                $sub_entities = $this->subEntities();
158
159 55
                if (isset($sub_entities[$property_name])) {
160 14
                    $class = $sub_entities[$property_name];
161
162 14
                    if (is_array($class)) {
163 1
                        return $this->makePrettyObjectArray(reset($class), $property_name);
164
                    }
165
166 13
                    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

166
                    return Factory::resolveEntityClass($class, $property, /** @scrutinizer ignore-type */ $this->getProperty('bot_username'));
Loading history...
167
                }
168
169 58
                return $property;
170
            }
171 2
        } elseif ($action === 'set') {
172
            // Limit setters to specific classes.
173 2
            if ($this instanceof InlineEntity || $this instanceof InputMedia || $this instanceof Keyboard || $this instanceof KeyboardButton) {
174 2
                $this->$property_name = $args[0];
175 2
                $this->raw_data[$property_name] = $args[0];
0 ignored issues
show
Bug Best Practice introduced by
The property raw_data does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
176
177 2
                return $this;
178
            }
179
        }
180
181 30
        return null;
182
    }
183
184
    /**
185
     * BC for renamed thumb -> thumbnail methods and fields
186
     *
187
     * @todo Remove after a few versions.
188
     *
189
     * @param string $name
190
     * @return string
191
     */
192 79
    protected function fixThumbnailRename(string $name): string
193
    {
194 79
        return self::$fixThumbnailRename ? preg_replace('/([Tt])humb(nail)?/', '$1humbnail', $name, -1, $count) : $name;
195
196
        /*if ($count) {
197
            // Notify user that there are still outdated method calls?
198
        }*/
199
    }
200
201
    /**
202
     * Return an array of nice objects from an array of object arrays
203
     *
204
     * This method is used to generate pretty object arrays
205
     * mainly for PhotoSize and Entities object arrays.
206
     *
207
     * @param string $class
208
     * @param string $property_name
209
     *
210
     * @return array
211
     */
212 1
    protected function makePrettyObjectArray(string $class, string $property_name): array
213
    {
214 1
        $objects      = [];
215 1
        $bot_username = $this->getProperty('bot_username');
216
217 1
        $properties = array_filter($this->getProperty($property_name) ?: []);
218 1
        foreach ($properties as $property) {
219 1
            $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

219
            $objects[] = Factory::resolveEntityClass($class, $property, /** @scrutinizer ignore-type */ $bot_username);
Loading history...
220
        }
221
222 1
        return $objects;
223
    }
224
225
    /**
226
     * Escape markdown (v1) special characters
227
     *
228
     * @see https://core.telegram.org/bots/api#markdown-style
229
     *
230
     * @param string $string
231
     *
232
     * @return string
233
     */
234 2
    public static function escapeMarkdown(string $string): string
235
    {
236 2
        return str_replace(
237 2
            ['[', '`', '*', '_',],
238 2
            ['\[', '\`', '\*', '\_',],
239 2
            $string
240 2
        );
241
    }
242
243
    /**
244
     * Escape markdown (v2) special characters
245
     *
246
     * @see https://core.telegram.org/bots/api#markdownv2-style
247
     *
248
     * @param string $string
249
     *
250
     * @return string
251
     */
252 1
    public static function escapeMarkdownV2(string $string): string
253
    {
254 1
        return str_replace(
255 1
            ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'],
256 1
            ['\_', '\*', '\[', '\]', '\(', '\)', '\~', '\`', '\>', '\#', '\+', '\-', '\=', '\|', '\{', '\}', '\.', '\!'],
257 1
            $string
258 1
        );
259
    }
260
261
    /**
262
     * Try to mention the user
263
     *
264
     * Mention the user with the username otherwise print first and last name
265
     * if the $escape_markdown argument is true special characters are escaped from the output
266
     *
267
     * @todo What about MarkdownV2?
268
     *
269
     * @param bool $escape_markdown
270
     *
271
     * @return string
272
     */
273 3
    public function tryMention($escape_markdown = false): string
274
    {
275
        // TryMention only makes sense for the User and Chat entity.
276 3
        if (!($this instanceof User || $this instanceof Chat)) {
277
            return '';
278
        }
279
280
        //Try with the username first...
281 3
        $name        = $this->getProperty('username');
282 3
        $is_username = $name !== null;
283
284 3
        if ($name === null) {
285
            //...otherwise try with the names.
286 3
            $name      = $this->getProperty('first_name');
287 3
            $last_name = $this->getProperty('last_name');
288 3
            if ($last_name !== null) {
289 3
                $name .= ' ' . $last_name;
290
            }
291
        }
292
293 3
        if ($escape_markdown) {
294 1
            $name = self::escapeMarkdown($name);
295
        }
296
297 3
        return ($is_username ? '@' : '') . $name;
298
    }
299
}
300