Completed
Push — master ( 61a289...e99580 )
by Camilo
13:30 queued 02:45
created

TelegramMethods   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 82.69%

Importance

Changes 0
Metric Value
dl 0
loc 159
ccs 43
cts 52
cp 0.8269
rs 10
c 0
b 0
f 0
wmc 21
lcom 1
cbo 6

7 Methods

Rating   Name   Duplication   Size   Complexity  
A bindToObject() 0 4 1
A performSpecialConditions() 0 8 2
B export() 0 25 4
A mandatoryUserOrInlineMessageId() 0 14 4
A formatReplyMarkup() 0 10 3
B getArrayFromKeyboard() 0 22 4
A exportReplyMarkupItem() 0 12 3
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace unreal4u\TelegramAPI\Abstracts;
6
7
use Psr\Log\LoggerInterface;
8
use unreal4u\TelegramAPI\Exceptions\MissingMandatoryField;
9
use unreal4u\TelegramAPI\Interfaces\TelegramMethodDefinitions;
10
use unreal4u\TelegramAPI\InternalFunctionality\TelegramResponse;
11
use unreal4u\TelegramAPI\Telegram\Types\Inline\Keyboard\Markup;
12
use unreal4u\TelegramAPI\Telegram\Types\Message;
13
use unreal4u\TelegramAPI\Telegram\Types\ReplyKeyboardMarkup;
14
15
/**
16
 * Contains methods that all Telegram methods should implement
17
 */
18
abstract class TelegramMethods implements TelegramMethodDefinitions
19
{
20
    /**
21
     * @var TelegramResponse
22
     */
23
    protected $response;
24
25
    /**
26
     * Most of the methods will return a Message object on success, so set that as the default.
27
     *
28
     * This function may however be overwritten if the method uses another object, there are many examples of this, so
29
     * just check out the rest of the code. A good place to start is GetUserProfilePhotos or LeaveChat
30
     *
31
     * @see \unreal4u\TelegramAPI\Telegram\Methods\GetUserProfilePhotos
32
     * @see \unreal4u\TelegramAPI\Telegram\Methods\LeaveChat
33
     *
34
     * @param TelegramResponse $data
35
     * @param LoggerInterface $logger
36
     *
37
     * @return TelegramTypes
38
     */
39 9
    public static function bindToObject(TelegramResponse $data, LoggerInterface $logger): TelegramTypes
40
    {
41 9
        return new Message($data->getResult(), $logger);
42
    }
43
44
    /**
45
     * Before making the actual request this method will be called
46
     *
47
     * It must be used to json_encode stuff, or do other changes in the internal class representation _before_ sending
48
     * it to the Telegram servers
49
     *
50
     * @return TelegramMethods
51
     */
52 32
    public function performSpecialConditions(): TelegramMethods
53
    {
54 32
        if (!empty($this->reply_markup)) {
55 1
            $this->reply_markup = json_encode($this->formatReplyMarkup($this->reply_markup));
0 ignored issues
show
Bug introduced by
The property reply_markup does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
56
        }
57
58 32
        return $this;
59
    }
60
61
    /**
62
     * Exports the class to an array in order to send it to the Telegram servers without extra fields that we don't need
63
     *
64
     * @return array
65
     * @throws MissingMandatoryField
66
     */
67 38
    final public function export(): array
68
    {
69 38
        $finalArray = [];
70 38
        $mandatoryFields = $this->getMandatoryFields();
71
72 38
        $cleanObject = new $this();
73 38
        foreach ($cleanObject as $fieldId => $value) {
74 38
            if ($this->$fieldId === $cleanObject->$fieldId) {
75 38
                if (\in_array($fieldId, $mandatoryFields, true)) {
76 6
                    $missingMandatoryField = new MissingMandatoryField(sprintf(
77 6
                        'The field "%s" for class "%s" is mandatory and empty, please correct',
78 6
                        $fieldId,
79 6
                        \get_class($cleanObject)
80
                    ));
81 6
                    $missingMandatoryField->method = \get_class($cleanObject);
82 6
                    $missingMandatoryField->methodInstance = $this;
83 38
                    throw $missingMandatoryField;
84
                }
85
            } else {
86 34
                $finalArray[$fieldId] = $this->$fieldId;
87
            }
88
        }
89
90 32
        return $finalArray;
91
    }
92
93
    /**
94
     * Will resolve the dependency of a mandatory inline_message_id OR a chat_id + message_id
95
     *
96
     * NOTE: This will use pass by reference instead of copy on write as the use-case for this functions allows this
97
     *
98
     * @param array $return
99
     * @return array
100
     */
101 4
    final protected function mandatoryUserOrInlineMessageId(array &$return): array
102
    {
103 4
        if (empty($this->chat_id) && empty($this->message_id)) {
0 ignored issues
show
Bug introduced by
The property chat_id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property message_id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
104 3
            $return[] = 'inline_message_id';
105
        }
106
107
        // On the other hand, chat_id and message_id are mandatory if inline_message_id is not filled in
108 4
        if (empty($this->inline_message_id)) {
0 ignored issues
show
Bug introduced by
The property inline_message_id does not seem to exist. Did you mean message_id?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
109 3
            $return[] = 'chat_id';
110 3
            $return[] = 'message_id';
111
        }
112
113 4
        return $return;
114
    }
115
116
    /**
117
     * ReplyMarkup fields require a bit of work before sending them
118
     *
119
     * This happens because reply markup are a type thus they don't have an export mechanism to do the job
120
     *
121
     * @param TelegramTypes $replyMarkup
122
     * @return TelegramTypes
123
     */
124 1
    final private function formatReplyMarkup(TelegramTypes $replyMarkup): TelegramTypes
125
    {
126 1
        if ($replyMarkup instanceof Markup) {
127
            $replyMarkup->inline_keyboard = $this->getArrayFromKeyboard($replyMarkup->inline_keyboard);
128 1
        } elseif ($replyMarkup instanceof ReplyKeyboardMarkup) {
129 1
            $replyMarkup->keyboard = $this->getArrayFromKeyboard($replyMarkup->keyboard);
130
        }
131
132 1
        return $replyMarkup;
133
    }
134
135 1
    final private function getArrayFromKeyboard(array $keyboardArray): array
136
    {
137 1
        $finalCleanArray = [];
138
139
        // A keyboard is an array of an array of objects or strings
140 1
        foreach ($keyboardArray as $rowItems) {
141 1
            $elements = [];
142 1
            foreach ($rowItems as $rowItem) {
143 1
                if (\is_object($rowItem)) {
144
                    // Button is effectively an object
145
                    $elements[] = $this->exportReplyMarkupItem($rowItem);
146
                } else {
147
                    // Add support for old style simple text buttons
148 1
                    $elements[] = $rowItem;
149
                }
150
            }
151
152 1
            $finalCleanArray[] = $elements;
153
        }
154
155 1
        return $finalCleanArray;
156
    }
157
158
    /**
159
     * Does the definitive export of those fields in a reply markup item that are filled in
160
     *
161
     * @param TelegramTypes $markupItem
162
     * @return array
163
     */
164
    final private function exportReplyMarkupItem(TelegramTypes $markupItem): array
165
    {
166
        $finalArray = [];
167
        $cleanObject = new $markupItem;
168
        foreach ($markupItem as $fieldId => $value) {
0 ignored issues
show
Bug introduced by
The expression $markupItem of type object<unreal4u\Telegram...bstracts\TelegramTypes> is not traversable.
Loading history...
169
            if ($markupItem->$fieldId !== $cleanObject->$fieldId) {
170
                $finalArray[$fieldId] = $markupItem->$fieldId;
171
            }
172
        }
173
174
        return $finalArray;
175
    }
176
}
177