Passed
Pull Request — master (#11)
by Thomas
10:32
created

RequestBuilder::isMultipart()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 2
rs 10
cc 2
nc 2
nop 0
1
<?php
2
/**
3
 * Copyright © Thomas Klein, All rights reserved.
4
 * See LICENSE bundled with this library for license details.
5
 */
6
declare(strict_types=1);
7
8
namespace Zoho\Desk\Client;
9
10
use Zoho\OAuth\Utility\ZohoOAuthConstants;
11
use Zoho\Desk\Api\Metadata;
12
use Zoho\Desk\Exception\Exception;
13
use Zoho\Desk\Exception\InvalidArgumentException;
14
use Zoho\Desk\OAuth\ClientInterface;
15
use function array_merge;
16
use function curl_init;
17
use function curl_setopt;
18
use function http_build_query;
19
use function is_array;
20
use function is_numeric;
21
use function json_encode;
22
use function sprintf;
23
use const CURLOPT_CUSTOMREQUEST;
24
use const CURLOPT_HEADER;
25
use const CURLOPT_HTTPHEADER;
26
use const CURLOPT_URL;
27
28
/**
29
 * @api
30
 */
31
final class RequestBuilder
32
{
33
    public const HTTP_GET = 'GET';
34
    public const HTTP_POST = 'POST';
35
    public const HTTP_PATCH = 'PATCH';
36
    public const HTTP_DELETE = 'DELETE';
37
38
    private const MANDATORY_FIELDS = ['entityType', 'method'];
39
40
    private ClientInterface $client;
41
42
    /**
43
     * @var resource
44
     */
45
    private $curl;
46
47
    /**
48
     * @var string[]
49
     */
50
    private array $mandatoryData;
51
52
    /**
53
     * @var array
54
     */
55
    private array $data;
56
57
    public function __construct(ClientInterface $client, array $mandatoryData = [])
58
    {
59
        $this->client = $client;
60
        $this->mandatoryData = array_merge(self::MANDATORY_FIELDS, $mandatoryData);
61
        $this->data = [];
62
    }
63
64
    public function setEntityType(string $entityType): self
65
    {
66
        $this->data['entityType'] = $entityType;
67
68
        return $this;
69
    }
70
71
    public function setMethod(string $method): self
72
    {
73
        $this->data['method'] = $method;
74
75
        return $this;
76
    }
77
78
    public function setArguments(array $arguments): self
79
    {
80
        $this->data['arguments'] = $arguments;
81
82
        return $this;
83
    }
84
85
    public function setQueryParameters(array $params): self
86
    {
87
        $this->data['queryParameters'] = $params;
88
89
        return $this;
90
    }
91
92
    public function setFields(array $fields): self
93
    {
94
        $this->data['fields'] = $fields;
95
96
        return $this;
97
    }
98
99
    /**
100
     * @return RequestInterface
101
     * @throws InvalidArgumentException|Exception
102
     */
103
    public function create(): RequestInterface
104
    {
105
        foreach ($this->mandatoryData as $mandatory) {
106
            if (!isset($this->data[$mandatory])) {
107
                throw InvalidArgumentException::createMandatoryFieldException($mandatory);
108
            }
109
        }
110
111
        $this->curl = curl_init();
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_init() can also be of type CurlHandle. However, the property $curl is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
112
        curl_setopt($this->curl, CURLOPT_URL, $this->buildUrl());
113
        curl_setopt($this->curl, CURLOPT_COOKIESESSION, true);
114
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
115
        curl_setopt($this->curl, CURLOPT_HEADER, 1);
116
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->buildHeaders());
117
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $this->data['method']);
118
119
        if ($this->data['method'] !== self::HTTP_GET) {
120
            curl_setopt($this->curl, CURLOPT_POST, true);
121
            if ($this->isMultipart()) {
122
                curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->data['fields']);
123
            } else {
124
                curl_setopt($this->curl, CURLOPT_POSTFIELDS, json_encode($this->data['fields']));
125
            }
126
        }
127
128
        $request = new Request($this->curl);
129
130
        $this->curl = null;
131
        $this->data = [];
132
133
        return $request;
134
    }
135
136
    /**
137
     * @return string[]
138
     * @throws Exception
139
     */
140
    private function buildHeaders(): array
141
    {
142
        $headers = [
143
            ZohoOAuthConstants::AUTHORIZATION . ':' . ZohoOAuthConstants::OAUTH_HEADER_PREFIX . $this->client->getAccessToken(),
144
            'Content-Type: ' . ($this->isMultipart() ? 'multipart/form-data' : 'application/json'),
145
        ];
146
147
        if ($this->client->getOrgId()) {
148
            $headers[] = Metadata::ORG_ID . ':' . $this->client->getOrgId();
149
        }
150
151
        return $headers;
152
    }
153
154
    private function isMultipart() {
155
        return isset($this->data['fields']['file']) && $this->data['fields']['file'] instanceof \CURLFile;
156
    }
157
158
    private function buildUrl(): string
159
    {
160
        $url = sprintf(
161
            'https://%s/%s/%s',
162
            $this->client->getApiBaseUrl(),
163
            $this->client->getApiVersion(),
164
            $this->data['entityType']
165
        );
166
167
        if (isset($this->data['arguments']) && is_array($this->data['arguments'])) {
168
            foreach ($this->data['arguments'] as $key => $argument) {
169
                if (!is_numeric($key)) {
170
                    $url .= '/' . $key;
171
                }
172
                $url .= '/' . $argument;
173
            }
174
        }
175
        if (isset($this->data['queryParameters']) && is_array($this->data['queryParameters'])) {
176
            $url .= '?' . http_build_query($this->data['queryParameters']);
177
        }
178
179
        return $url;
180
    }
181
}
182