Completed
Push — master ( 22d446...d75bd7 )
by Camilo
01:58
created

TelegramMethods::formatReplyMarkup()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.3332

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 4
cts 6
cp 0.6667
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 3.3332
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 31
    public function performSpecialConditions(): TelegramMethods
53
    {
54 31
        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 31
        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 37
    final public function export(): array
68
    {
69 37
        $finalArray = [];
70 37
        $mandatoryFields = $this->getMandatoryFields();
71
72 37
        $cleanObject = new $this();
73 37
        foreach ($cleanObject as $fieldId => $value) {
74 37
            if ($this->$fieldId === $cleanObject->$fieldId) {
75 37
                if (in_array($fieldId, $mandatoryFields, true)) {
76 6
                    throw new MissingMandatoryField(sprintf(
77 37
                        'The field "%s" is mandatory and empty, please correct',
78
                        $fieldId
79
                    ));
80
                }
81
            } else {
82 33
                $finalArray[$fieldId] = $this->$fieldId;
83
            }
84
        }
85
86 31
        return $finalArray;
87
    }
88
89
    /**
90
     * Will resolve the dependency of a mandatory inline_message_id OR a chat_id + message_id
91
     *
92
     * NOTE: This will use pass by reference instead of copy on write as the use-case for this functions allows this
93
     *
94
     * @param array $return
95
     * @return array
96
     */
97 4
    final protected function mandatoryUserOrInlineMessageId(array &$return): array
98
    {
99 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...
100 3
            $return[] = 'inline_message_id';
101
        }
102
103
        // On the other hand, chat_id and message_id are mandatory if inline_message_id is not filled in
104 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...
105 3
            $return[] = 'chat_id';
106 3
            $return[] = 'message_id';
107
        }
108
109 4
        return $return;
110
    }
111
112
    /**
113
     * ReplyMarkup fields require a bit of work before sending them
114
     *
115
     * This happens because reply markup are a type thus they don't have an export mechanism to do the job
116
     *
117
     * @param TelegramTypes $replyMarkup
118
     * @return TelegramTypes
119
     */
120 1
    final private function formatReplyMarkup(TelegramTypes $replyMarkup): TelegramTypes
121
    {
122 1
        if ($replyMarkup instanceof Markup) {
123
            $replyMarkup->inline_keyboard = $this->getArrayFromKeyboard($replyMarkup->inline_keyboard);
124
        } elseif ($replyMarkup instanceof ReplyKeyboardMarkup) {
125 1
            $replyMarkup->keyboard = $this->getArrayFromKeyboard($replyMarkup->keyboard);
126
        }
127
128 1
        return $replyMarkup;
129
    }
130
131 1
    final private function getArrayFromKeyboard(array $keyboardArray): array
132
    {
133 1
        $finalCleanArray = [];
134
135
        // A keyboard is an array of an array of objects or strings
136 1
        foreach ($keyboardArray as $rowItems) {
137 1
            $elements = [];
138 1
            foreach ($rowItems as $rowItem) {
139 1
                if (is_object($rowItem)) {
140
                    // Button is effectively an object
141
                    $elements[] = $this->exportReplyMarkupItem($rowItem);
142
                } else {
143
                    // Add support for old style simple text buttons
144 1
                    $elements[] = $rowItem;
145
                }
146
            }
147
148 1
            $finalCleanArray[] = $elements;
149
        }
150
151 1
        return $finalCleanArray;
152
    }
153
154
    /**
155
     * Does the definitive export of those fields in a reply markup item that are filled in
156
     *
157
     * @param TelegramTypes $markupItem
158
     * @return array
159
     */
160
    final private function exportReplyMarkupItem(TelegramTypes $markupItem): array
161
    {
162
        $finalArray = [];
163
        $cleanObject = new $markupItem;
164
        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...
165
            if ($markupItem->$fieldId !== $cleanObject->$fieldId) {
166
                $finalArray[$fieldId] = $markupItem->$fieldId;
167
            }
168
        }
169
170
        return $finalArray;
171
    }
172
}
173