Completed
Pull Request — master (#53)
by Rick
02:35
created

TelegramMethods   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 81.25%

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 6
dl 0
loc 163
ccs 39
cts 48
cp 0.8125
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A bindToObject() 0 4 1
A performSpecialConditions() 0 21 2
A mandatoryUserOrInlineMessageId() 0 14 4
B getArrayFromKeyboard() 0 22 4
A exportReplyMarkupItem() 0 12 3
A export() 0 21 4
A formatReplyMarkup() 0 10 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\TelegramRawData;
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
     * Most of the methods will return a Message object on success, so set that as the default.
22
     *
23
     * This function may however be overwritten if the method uses another object, there are many examples of this, so
24
     * just check out the rest of the code. A good place to start is GetUserProfilePhotos or LeaveChat
25
     *
26
     * @see \unreal4u\TelegramAPI\Telegram\Methods\GetUserProfilePhotos
27
     * @see \unreal4u\TelegramAPI\Telegram\Methods\LeaveChat
28
     *
29
     * @param TelegramRawData $data
30
     * @param LoggerInterface $logger
31
     *
32
     * @return TelegramTypes
33
     */
34 9
    public static function bindToObject(TelegramRawData $data, LoggerInterface $logger): TelegramTypes
35
    {
36 9
        return new Message($data->getResult(), $logger);
37
    }
38
39
    /**
40
     * Before making the actual request this method will be called
41
     *
42
     * It must be used to json_encode stuff, or do other changes in the internal class representation _before_ sending
43
     * it to the Telegram servers
44
     *
45
     * @return TelegramMethods
46
     */
47 30
    public function performSpecialConditions(): TelegramMethods
48
    {
49 30
        if (!empty($this->reply_markup)) {
50 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...
51
        }
52
53
        // Several classes may send a parse mode, so check before sending
54
        // TODO Do I want to validate data in here? Should I?
55
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% 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...
56
         * if (!empty($this->parse_mode)) {
57
            if (strtoupper($this->parse_mode) !== 'HTML' || strtoupper($this->parse_mode) !== 'MARKDOWN') {
58
                throw new InvalidParseMode(sprintf(
59
                    'An invalid value for parse_mode has been given. Please use HTML or Markdown. Provided: "%s"',
60
                    $this->parse_mode
61
                ));
62
            }
63
        }
64
         */
65
66 30
        return $this;
67
    }
68
69
    /**
70
     * Exports the class to an array in order to send it to the Telegram servers without extra fields that we don't need
71
     *
72
     * @return array
73
     * @throws MissingMandatoryField
74
     */
75 36
    final public function export(): array
76
    {
77 36
        $finalArray = [];
78 36
        $mandatoryFields = $this->getMandatoryFields();
79
80 36
        $cleanObject = new $this();
81 36
        foreach ($cleanObject as $fieldId => $value) {
82 32
            if ($this->$fieldId === $cleanObject->$fieldId) {
83 30
                if (in_array($fieldId, $mandatoryFields, true)) {
84 6
                    throw new MissingMandatoryField(sprintf(
85 6
                        'The field "%s" is mandatory and empty, please correct',
86 30
                        $fieldId
87
                    ));
88
                }
89
            } else {
90 28
                $finalArray[$fieldId] = $this->$fieldId;
91
            }
92
        }
93
94 30
        return $finalArray;
95
    }
96
97
    /**
98
     * Will resolve the dependency of a mandatory inline_message_id OR a chat_id + message_id
99
     *
100
     * NOTE: This will use pass by reference instead of copy on write as the use-case for this functions allows this
101
     *
102
     * @param array $return
103
     * @return array
104
     */
105 4
    final protected function mandatoryUserOrInlineMessageId(array &$return): array
106
    {
107 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...
108 3
            $return[] = 'inline_message_id';
109
        }
110
111
        // On the other hand, chat_id and message_id are mandatory if inline_message_id is not filled in
112 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...
113 3
            $return[] = 'chat_id';
114 3
            $return[] = 'message_id';
115
        }
116
117 4
        return $return;
118
    }
119
120
    /**
121
     * ReplyMarkup fields require a bit of work before sending them
122
     *
123
     * This happens because reply markup are a type thus they don't have an export mechanism to do the job
124
     *
125
     * @param TelegramTypes $replyMarkup
126
     * @return TelegramTypes
127
     */
128 1
    final private function formatReplyMarkup(TelegramTypes $replyMarkup): TelegramTypes
129
    {
130 1
        if ($replyMarkup instanceof Markup) {
131
            $replyMarkup->inline_keyboard = $this->getArrayFromKeyboard($replyMarkup->inline_keyboard);
132 1
        } elseif ($replyMarkup instanceof ReplyKeyboardMarkup) {
133 1
            $replyMarkup->keyboard = $this->getArrayFromKeyboard($replyMarkup->keyboard);
134
        }
135
136 1
        return $replyMarkup;
137
    }
138
139 1
    final private function getArrayFromKeyboard(array $keyboardArray): array
140
    {
141 1
        $finalCleanArray = [];
142
143
        // A keyboard is an array of an array of objects or strings
144 1
        foreach ($keyboardArray as $rowItems) {
145 1
            $elements = [];
146 1
            foreach ($rowItems as $rowItem) {
147 1
                if (is_object($rowItem)) {
148
                    // Button is effectively an object
149
                    $elements[] = $this->exportReplyMarkupItem($rowItem);
150
                } else {
151
                    // Add support for old style simple text buttons
152 1
                    $elements[] = $rowItem;
153
                }
154
            }
155
156 1
            $finalCleanArray[] = $elements;
157
        }
158
159 1
        return $finalCleanArray;
160
    }
161
162
    /**
163
     * Does the definitive export of those fields in a reply markup item that are filled in
164
     *
165
     * @param TelegramTypes $markupItem
166
     * @return array
167
     */
168
    final private function exportReplyMarkupItem(TelegramTypes $markupItem): array
169
    {
170
        $finalArray = [];
171
        $cleanObject = new $markupItem;
172
        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...
173
            if ($markupItem->$fieldId !== $cleanObject->$fieldId) {
174
                $finalArray[$fieldId] = $markupItem->$fieldId;
175
            }
176
        }
177
178
        return $finalArray;
179
    }
180
}
181