Passed
Pull Request — master (#8)
by Thomas
01:37
created

RequestBuilder::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 2
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
16
use function array_keys;
17
use function array_map;
18
use function array_merge;
19
use function array_values;
20
use function curl_init;
21
use function curl_setopt;
22
use function http_build_query;
23
use function is_array;
24
use function is_numeric;
25
use function json_encode;
26
use function sprintf;
27
use function str_replace;
28
29
use const CURLOPT_CUSTOMREQUEST;
30
use const CURLOPT_HEADER;
31
use const CURLOPT_HTTPHEADER;
32
use const CURLOPT_URL;
33
34
/**
35
 * @api
36
 */
37
final class RequestBuilder
38
{
39
    public const HTTP_GET = 'GET';
40
    public const HTTP_POST = 'POST';
41
    public const HTTP_PATCH = 'PATCH';
42
    public const HTTP_DELETE = 'DELETE';
43
44
    private const MANDATORY_FIELDS = ['entityType', 'method'];
45
46
    private ClientInterface $client;
47
48
    /**
49
     * @var resource
50
     */
51
    private $curl;
52
53
    /**
54
     * @var string[]
55
     */
56
    private array $mandatoryData;
57
58
    /**
59
     * @var array
60
     */
61
    private array $data;
62
63
    public function __construct(ClientInterface $client, array $mandatoryData = [])
64
    {
65
        $this->client = $client;
66
        $this->mandatoryData = array_merge(self::MANDATORY_FIELDS, $mandatoryData);
67
        $this->data = [];
68
    }
69
70
    /**
71
     * @deprecated
72
     */
73
    public function setEntityType(string $entityType): self
74
    {
75
        $this->data['entityType'] = $entityType;
76
77
        return $this;
78
    }
79
80
    public function setPath(string $path, array $bind = []): self
81
    {
82
        $search = array_map(static function (string $variable): string {
83
            return '{' . $variable . '}';
84
        }, array_keys($bind));
85
86
        $this->data['path'] = str_replace($search, array_values($bind), $path);
87
88
        return $this;
89
    }
90
91
    public function setMethod(string $method): self
92
    {
93
        $this->data['method'] = $method;
94
95
        return $this;
96
    }
97
98
    public function setArguments(array $arguments): self
99
    {
100
        $this->data['arguments'] = $arguments;
101
102
        return $this;
103
    }
104
105
    public function setQueryParameters(array $params): self
106
    {
107
        $this->data['queryParameters'] = $params;
108
109
        return $this;
110
    }
111
112
    public function setFields(array $fields): self
113
    {
114
        $this->data['fields'] = $fields;
115
116
        return $this;
117
    }
118
119
    /**
120
     * @return RequestInterface
121
     * @throws InvalidArgumentException|Exception
122
     */
123
    public function create(): RequestInterface
124
    {
125
        foreach ($this->mandatoryData as $mandatory) {
126
            if (!isset($this->data[$mandatory])) {
127
                throw InvalidArgumentException::createMandatoryFieldException($mandatory);
128
            }
129
        }
130
131
        $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...
132
        curl_setopt($this->curl, CURLOPT_URL, $this->buildUrl());
133
        curl_setopt($this->curl, CURLOPT_COOKIESESSION, true);
134
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
135
        curl_setopt($this->curl, CURLOPT_HEADER, 1);
136
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->buildHeaders());
137
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $this->data['method']);
138
139
        if ($this->data['method'] !== self::HTTP_GET) {
140
            curl_setopt($this->curl, CURLOPT_POST, true);
141
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, json_encode($this->data['fields']));
142
        }
143
144
        $request = new Request($this->curl);
145
146
        $this->curl = null;
147
        $this->data = [];
148
149
        return $request;
150
    }
151
152
    /**
153
     * @return string[]
154
     * @throws Exception
155
     */
156
    private function buildHeaders(): array
157
    {
158
        $headers = [
159
            ZohoOAuthConstants::AUTHORIZATION . ':' . ZohoOAuthConstants::OAUTH_HEADER_PREFIX . $this->client->getAccessToken(),
160
            'Content-Type:application/json'
161
        ];
162
163
        if ($this->client->getOrgId()) {
164
            $headers[] = Metadata::ORG_ID . ':' . $this->client->getOrgId();
165
        }
166
167
        return $headers;
168
    }
169
170
    private function buildUrl(): string
171
    {
172
        $url = sprintf(
173
            'https://%s/%s/%s',
174
            $this->client->getApiBaseUrl(),
175
            $this->client->getApiVersion(),
176
            $this->data['path'] ?? $this->data['entityType']
177
        );
178
179
        if (isset($this->data['arguments']) && is_array($this->data['arguments'])) {
180
            foreach ($this->data['arguments'] as $key => $argument) {
181
                if (!is_numeric($key)) {
182
                    $url .= '/' . $key;
183
                }
184
                $url .= '/' . $argument;
185
            }
186
        }
187
        if (isset($this->data['queryParameters']) && is_array($this->data['queryParameters'])) {
188
            $url .= '?' . http_build_query($this->data['queryParameters']);
189
        }
190
191
        return $url;
192
    }
193
}
194