Completed
Pull Request — develop (#291)
by Armando
03:42
created

Entity   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 305
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 80.56%

Importance

Changes 0
Metric Value
wmc 51
lcom 1
cbo 0
dl 0
loc 305
ccs 87
cts 108
cp 0.8056
rs 8.3206
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getBotName() 0 4 1
A __construct() 0 6 1
A toJson() 0 4 1
C reflect() 0 69 20
A __toString() 0 4 1
A assignMemberVariables() 0 6 2
A subEntities() 0 4 1
A validate() 0 3 1
A getProperty() 0 8 2
B makePrettyObjectArray() 0 18 5
C __call() 0 30 8
A escapeMarkdown() 0 8 1
C tryMention() 0 30 7

How to fix   Complexity   

Complex Class

Complex classes like Entity often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Entity, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This file is part of the TelegramBot package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\TelegramBot\Entities;
12
13
use Exception;
14
use Longman\TelegramBot\Entities\InlineQuery\InlineEntity;
15
use ReflectionObject;
16
17
/**
18
 * Class Entity
19
 *
20
 * This is the base class for all entities.
21
 */
22
abstract class Entity
23
{
24
    /**
25
     * @var string
26
     */
27
    protected $bot_name;
28
29
    /**
30
     * Get bot name
31
     *
32
     * @return string
33
     */
34
    public function getBotName()
35
    {
36
        return $this->bot_name;
37
    }
38
39
    /**
40
     * Entity constructor.
41
     *
42
     * @todo Get rid of the $bot_name, it shouldn't be here!
43
     *
44
     * @param        $data
45
     * @param string $bot_name
46
     *
47
     * @throws \Longman\TelegramBot\Exception\TelegramException
48
     */
49 58
    public function __construct($data, $bot_name = '')
50
    {
51 58
        $this->assignMemberVariables($data);
52 58
        $this->validate();
53 49
        $this->bot_name = $bot_name;
54 49
    }
55
56
    /**
57
     * Perform to json
58
     *
59
     * @return string
60
     */
61 1
    public function toJson()
62
    {
63 1
        return json_encode($this->reflect($this));
64
    }
65
66
    /**
67
     * Reflect
68
     *
69
     * @param null $object
70
     *
71
     * @return array
72
     */
73 1
    public function reflect($object = null)
74
    {
75 1
        if ($object === null) {
76
            $object = $this;
77
        }
78
79 1
        $reflection = new ReflectionObject($object);
80 1
        $properties = $reflection->getProperties();
81
82 1
        $fields = [];
83
84 1
        foreach ($properties as $property) {
85 1
            $name = $property->getName();
86 1
            if ($name === 'bot_name') {
87 1
                continue;
88
            }
89
90 1
            if (!$property->isPrivate()) {
91 1
                $array_of_obj       = false;
92 1
                $array_of_array_obj = false;
93 1
                if (is_array($object->$name)) {
94 1
                    $array_of_obj       = true;
95 1
                    $array_of_array_obj = true;
96 1
                    foreach ($object->$name as $elm) {
97 1
                        if (!is_object($elm)) {
98
                            //echo $name . " not array of object \n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
99 1
                            $array_of_obj = false;
100
                            //break;
101
                        }
102 1
                        if (is_array($elm)) {
103 1
                            foreach ($elm as $more_net) {
104 1
                                if (!is_object($more_net)) {
105 1
                                    $array_of_array_obj = false;
106
                                }
107
                            }
108
                        }
109
                    }
110
                }
111
112 1
                if (is_object($object->$name)) {
113
                    $fields[$name] = $this->reflect($object->$name);
114 1
                } elseif ($array_of_obj) {
115
                    foreach ($object->$name as $elm) {
116
                        $fields[$name][] = $this->reflect($elm);
117
                    }
118 1
                } elseif ($array_of_array_obj) {
119
                    foreach ($object->$name as $elm) {
120
                        $temp = null;
121
                        if (!is_array($elm) && !is_object($elm)) {
122
                            continue;
123
                        }
124
                        foreach ($elm as $obj) {
125
                            $temp[] = $this->reflect($obj);
126
                        }
127
                        $fields[$name][] = $temp;
128
                    }
129
                } else {
130 1
                    $property->setAccessible(true);
131 1
                    $value = $property->getValue($object);
132 1
                    if (null === $value) {
133
                        continue;
134
                    }
135 1
                    $fields[$name] = $value;
136
                }
137
            }
138
        }
139
140 1
        return $fields;
141
    }
142
143
    /**
144
     * Perform to string
145
     *
146
     * @return string
147
     */
148
    public function __toString()
149
    {
150
        return $this->toJson();
151
    }
152
153
    /**
154
     * Helper to set member variables
155
     *
156
     * @param array $data
157
     */
158 58
    protected function assignMemberVariables(array $data)
159
    {
160 58
        foreach ($data as $key => $value) {
161 56
            $this->$key = $value;
162
        }
163 58
    }
164
165
    /**
166
     * Get the list of the properties that are themselves Entities
167
     *
168
     * @return array
169
     */
170 36
    protected function subEntities()
171
    {
172 36
        return [];
173
    }
174
175
    /**
176
     * Perform any special entity validation
177
     *
178
     * @throws \Longman\TelegramBot\Exception\TelegramException
179
     */
180 31
    protected function validate()
181
    {
182 31
    }
183
184
    /**
185
     * Get a property from the current Entity
186
     *
187
     * @param mixed $property
188
     * @param mixed $default
189
     *
190
     * @return mixed
191
     */
192 53
    public function getProperty($property, $default = null)
193
    {
194 53
        if (isset($this->$property)) {
195 51
            return $this->$property;
196
        }
197
198 37
        return $default;
199
    }
200
201
    /**
202
     * Return the variable for the called getter or magically set properties dynamically.
203
     *
204
     * @param $method
205
     * @param $args
206
     *
207
     * @return mixed|null
208
     */
209 39
    public function __call($method, $args)
210
    {
211
        //Convert method to snake_case (which is the name of the property)
212 39
        $property_name = ltrim(strtolower(preg_replace('/[A-Z]/', '_$0', substr($method, 3))), '_');
213
214 39
        $action = substr($method, 0, 3);
215 39
        if ($action === 'get') {
216 39
            $property = $this->getProperty($property_name);
217
218 39
            if ($property !== null) {
219
                //Get all sub-Entities of the current Entity
220 39
                $sub_entities = $this->subEntities();
221
222 39
                if (isset($sub_entities[$property_name])) {
223 15
                    return new $sub_entities[$property_name]($property);
224
                }
225
226 38
                return $property;
227
            }
228 3
        } elseif ($action === 'set') {
229
            // Limit setters to specific classes.
230 3
            if ($this instanceof InlineEntity || $this instanceof Keyboard || $this instanceof KeyboardButton) {
231 3
                $this->$property_name = $args[0];
232
233 3
                return $this;
234
            }
235
        }
236
237 23
        return null;
238
    }
239
240
    /**
241
     * Return an array of nice objects from an array of object arrays
242
     *
243
     * This method is used to generate pretty object arrays
244
     * mainly for PhotoSize and Entities object arrays.
245
     *
246
     * @param string $class
247
     * @param string $property
248
     *
249
     * @return array
250
     */
251 6
    protected function makePrettyObjectArray($class, $property)
252
    {
253 6
        $new_objects = [];
254
255
        try {
256 6
            if ($objects = $this->getProperty($property)) {
257
                foreach ($objects as $object) {
258
                    if (!empty($object)) {
259 6
                        $new_objects[] = new $class($object);
260
                    }
261
                }
262
            }
263
        } catch (Exception $e) {
264
            $new_objects = [];
265
        }
266
267 6
        return $new_objects;
268
    }
269
270
    /**
271
     * Escape markdown special characters
272
     *
273
     * @param string $string
274
     *
275
     * @return string
276
     */
277 1
    public function escapeMarkdown($string)
278
    {
279 1
        return str_replace(
280 1
            ['[', '`', '*', '_',],
281 1
            ['\[', '\`', '\*', '\_',],
282
            $string
283
        );
284
    }
285
286
    /**
287
     * Try to mention the user
288
     *
289
     * Mention the user with the username otherwise print first and last name
290
     * if the $escape_markdown argument is true special characters are escaped from the output
291
     *
292
     * @param bool $escape_markdown
293
     *
294
     * @return string|null
295
     */
296 3
    public function tryMention($escape_markdown = false)
297
    {
298
        //TryMention only makes sense for the User and Chat entity.
299 3
        if (!($this instanceof User || $this instanceof Chat)) {
300
            return null;
301
        }
302
303
        //Try with the username first...
304 3
        $username = $this->getProperty('username');
305 3
        if ($username !== null) {
306 3
            if ($escape_markdown) {
307 1
                $username = $this->escapeMarkdown($username);
308
            }
309
310 3
            return '@' . $username;
311
        }
312
313
        //...otherwise try with the names
314 3
        $name      = $this->getProperty('first_name');
315 3
        $last_name = $this->getProperty('last_name');
316 3
        if ($last_name !== null) {
317 3
            $name .= ' ' . $last_name;
318
        }
319
320 3
        if ($escape_markdown) {
321 1
            $name = $this->escapeMarkdown($name);
322
        }
323
324 3
        return $name;
325
    }
326
}
327