Completed
Pull Request — master (#95)
by
unknown
04:48
created

PostOptionsConstructor::checkIsMultipart()   D

Complexity

Conditions 18
Paths 9

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 62.5396

Importance

Changes 0
Metric Value
cc 18
nc 9
nop 1
dl 0
loc 46
ccs 15
cts 31
cp 0.4839
crap 62.5396
rs 4.8666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types = 1);
4
5
namespace unreal4u\TelegramAPI\InternalFunctionality;
6
7
use MultipartBuilder\Builder;
8
use MultipartBuilder\MultipartData;
9
use Psr\Log\LoggerInterface;
10
use unreal4u\Dummy\Logger;
11
use unreal4u\TelegramAPI\Abstracts\TelegramMethods;
12
use unreal4u\TelegramAPI\Telegram\Types\Custom\InputFile;
13
use unreal4u\TelegramAPI\Telegram\Types\InputMedia\Photo;
14
15
class PostOptionsConstructor
16
{
17
    /**
18
     * With this flag we'll know what type of request to send to Telegram
19
     *
20
     * 'application/x-www-form-urlencoded' is the "normal" one, which is simpler and quicker.
21
     * 'multipart/form-data' should be used only when you upload documents, photos, etc.
22
     *
23
     * @var string
24
     */
25
    public $formType = 'application/x-www-form-urlencoded';
26
27
    /**
28
     * @var LoggerInterface
29
     */
30
    protected $logger;
31
32 41
    public function __construct(LoggerInterface $logger = null)
33
    {
34 41
        if ($logger === null) {
35 41
            $logger = new Logger();
36
        }
37 41
        $this->logger = $logger;
38 41
    }
39
40
    /**
41
     * Builds up the form elements to be sent to Telegram
42
     *
43
     * @TODO Move this to apart function
44
     *
45
     * @param TelegramMethods $method
46
     * @return array
47
     * @throws \unreal4u\TelegramAPI\Exceptions\MissingMandatoryField
48
     */
49 32
    public function constructOptions(TelegramMethods $method): array
50
    {
51 32
        $result = $this->checkIsMultipart($method);
52
53 32
        if (!empty($result)) {
54 4
            return $this->constructMultipartOptions(
55 4
                $method->export(),
56 4
                $result
57
            );
58
        }
59
60 28
        $body = http_build_query($method->export(), '', '&');
61
        
62
        return [
63
            'headers' => [
64 26
                'Content-Type' => 'application/x-www-form-urlencoded',
65 26
                'Content-Length' => \strlen($body),
66 26
                'User-Agent' => 'PHP7+ Bot API',
67
            ],
68 26
            'body' => $body
69
        ];
70
    }
71
72
    /**
73
     * Check if the given TelegramMethod should be handled as a multipart.
74
     *
75
     * @param TelegramMethods $method
76
     * @return array
77
     */
78 32
    private function checkIsMultipart(TelegramMethods $method): array
79
    {
80 32
        $this->logger->debug('Checking whether to apply special conditions to this request');
81 32
        $method->performSpecialConditions();
82
83 32
        $return = [];
84
85 32
        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...
86 28
            if ((\is_object($value) && $value instanceof InputFile)||(\is_object($value) && $value instanceof Photo)||((is_array($value) || $value instanceof Countable) && \count($value)>1 && (reset($value) instanceof InputFile||reset($value) instanceof Photo))) {
0 ignored issues
show
Bug introduced by
The class unreal4u\TelegramAPI\Int...Functionality\Countable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
87 4
                $this->logger->debug('About to send a file, so changing request to use multi-part instead');
88
                // If we are about to send a file, we must use the multipart/form-data way
89 4
                $this->formType = 'multipart/form-data';
90 4
                if($value instanceof InputFile){
91 4
                  $return[$key] = [
92 4
                      'id' => $key,
93 4
                      'filename' => $value->path,
94 4
                      'stream' => $value->getStream()
95
                  ];
96
                }elseif($value instanceof Photo){
97
                   $return[$key] = [
98
                      'id' => $key,
99
                      'filename' => $value->media->path,
100
                      'stream' => $value->media->getStream()
101
                  ];
102
                }elseif((is_array($value) || $value instanceof Countable)){
0 ignored issues
show
Bug introduced by
The class unreal4u\TelegramAPI\Int...Functionality\Countable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
103
                  foreach ($value as $kk => $vv){
104
                  if($vv instanceof InputFile){
105
                   $return[$kk] = [
106
                      'id' => $kk,
107
                      'filename' => $vv->path,
108
                      'stream' => $vv->getStream()
109
                  ];
110
                }elseif($vv instanceof Photo){
111
                    $return[$kk] = [
112
                      'id' => $kk,
113
                      'filename' => $vv->media->path,
114 28
                      'stream' => $vv->media->getStream()
0 ignored issues
show
Bug introduced by
The method getStream cannot be called on $vv->media (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
115
                  ];
116
                  }
117
                  }
118
                }
119
            }
120
        }
121
122 32
        return $return;
123
    }
124
125
    /**
126
     * Builds up a multipart form-like array for Guzzle
127
     *
128
     * @param array $data The original object in array form
129
     * @param string $fileKeyName A file handler will be sent instead of a string, state here which field it is
0 ignored issues
show
Bug introduced by
There is no parameter named $fileKeyName. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
130
     * @param resource $stream The actual file handler
0 ignored issues
show
Bug introduced by
There is no parameter named $stream. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
131
     * @param string $filename
0 ignored issues
show
Bug introduced by
There is no parameter named $filename. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
132
     * @return array Returns the actual formdata to be sent
133
     */
134 4
    public function constructMultipartOptions(array $data, array $multipart_data): array
135
    {
136 4
        $builder = new Builder();
137 4
        $this->logger->debug('Creating multi-part form array data (complex and expensive)');
138 4
        foreach ($data as $id => $value) {
0 ignored issues
show
Bug introduced by
The expression $data of type object<MultipartBuilder\MultipartData>|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
139 4
              if (array_key_exists($id,$multipart_data)) {
140 4
                $data = new MultipartData(
141 4
                    (string) $multipart_data[$id]['id'],
142 4
                    stream_get_contents($multipart_data[$id]['stream']),
143 4
                    pathinfo($multipart_data[$id]['filename'], PATHINFO_BASENAME)
144
                );
145 4
                $builder->append($data);
146 4
            } elseif($id=='mediagroup') {
147
               foreach($multipart_data as $ii => $mdata){
148
                $data = new MultipartData(
149
                    pathinfo($mdata['filename'], PATHINFO_BASENAME),
150
                    stream_get_contents($mdata['stream']),
151
                    pathinfo($mdata['filename'], PATHINFO_BASENAME)
152
                );
153
                $builder->append($data);
154
               }
155
            } else {
156 4
                $data = new MultipartData((string) $id, (string) $value);
157 4
                $builder->append($data);
158
            }
159
        }
160
161 4
        $body = $builder->buildAll();
162
        $array = [
163
            'headers' => [
164 4
                'Content-Type' => 'multipart/form-data; boundary="' . $builder->getBoundary() . '"',
165 4
                'Content-Length' => \strlen($body)
166
            ],
167 4
            'body' => $body
168
        ];
169 4
        return $array;
170
    }
171
}
172