Completed
Pull Request — master (#55)
by Rick
08:13
created

PostOptionsConstructor::constructOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace unreal4u\TelegramAPI\InternalFunctionality;
6
7
use Psr\Log\LoggerInterface;
8
use unreal4u\TelegramAPI\Abstracts\TelegramMethods;
9
use unreal4u\TelegramAPI\Telegram\Types\Custom\InputFile;
10
11
class PostOptionsConstructor
12
{
13
    /**
14
     * With this flag we'll know what type of request to send to Telegram
15
     *
16
     * 'application/x-www-form-urlencoded' is the "normal" one, which is simpler and quicker.
17
     * 'multipart/form-data' should be used only when you upload documents, photos, etc.
18
     *
19
     * @var string
20
     */
21
    public $formType = 'application/x-www-form-urlencoded';
22
23
    /**
24
     * @var LoggerInterface
25
     */
26
    protected $logger;
27
28
    public function __construct(LoggerInterface $logger = null)
29
    {
30
        if ($logger === null) {
31
            $logger = new DummyLogger();
32
        }
33
        $this->logger = $logger;
34
    }
35
36
    /**
37
     * Builds up the form elements to be sent to Telegram
38
     *
39
     * @TODO Move this to apart function
40
     *
41
     * @param TelegramMethods $method
42
     * @return array
43
     * @throws \unreal4u\TelegramAPI\Exceptions\MissingMandatoryField
44
     */
45
    public function constructOptions(TelegramMethods $method): array
46
    {
47
        $result = $this->checkIsMultipart($method);
48
49
        if (!empty($result)) {
50
            return $this->constructMultipartOptions($method->export(), $result['id'], $result['stream']);
51
        }
52
53
        return [
54
            'headers' => [
55
                'Content-Type' => 'application/x-www-form-urlencoded'
56
            ],
57
            'body' => http_build_query($method->export(), '', '&')
58
        ];
59
    }
60
61
    /**
62
     * Check if the given TelegramMethod should be handled as a multipart.
63
     *
64
     * @param TelegramMethods $method
65
     * @return array
66
     */
67
    private function checkIsMultipart(TelegramMethods $method): array
68
    {
69
        $this->logger->debug('Checking whether to apply special conditions to this request');
70
        $method->performSpecialConditions();
71
72
        $return = [];
73
74
        foreach ($method as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $method of type object<unreal4u\Telegram...tracts\TelegramMethods> is not traversable.
Loading history...
75
            if (is_object($value) && $value instanceof InputFile) {
76
                $this->logger->debug('About to send a file, so changing request to use multi-part instead');
77
                // If we are about to send a file, we must use the multipart/form-data way
78
                $this->formType = 'multipart/form-data';
79
                $return = [
80
                    'id' => $key,
81
                    'stream' => $value->getStream(),
82
                ];
83
            }
84
        }
85
86
        return $return;
87
    }
88
89
    /**
90
     * Builds up a multipart form-like array for Guzzle
91
     *
92
     * @param array $data The original object in array form
93
     * @param string $fileKeyName A file handler will be sent instead of a string, state here which field it is
94
     * @param resource $stream The actual file handler
95
     * @return array Returns the actual formdata to be sent
96
     */
97
    public function constructMultipartOptions(array $data, string $fileKeyName, $stream): array
98
    {
99
        $this->logger->debug('Creating multi-part form array data (complex and expensive)');
100
101
        $multiPartArray = [];
102
        foreach ($data as $id => $value) {
103
            // Always send as a string unless it's a file
104
            $multiPart = [
105
                'name' => $id,
106
                'contents' => null,
107
            ];
108
109
            if ($id === $fileKeyName) {
110
                $multiPart['contents'] = $stream;
111
            } else {
112
                $multiPart['contents'] = (string)$value;
113
            }
114
115
            $multiPartArray[] = $multiPart;
116
        }
117
118
        return [
119
            'headers' => [
120
                'Content-Type' => 'multipart/form-data'
121
            ],
122
            'body' => $multiPartArray
123
        ];
124
    }
125
}
126