Completed
Push — master ( c25259...12e411 )
by Jared
01:46
created

Xero::refreshToken()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
rs 9.2
cc 2
eloc 13
nc 2
nop 2
1
<?php
2
3
namespace Invoiced\OAuth1\Client\Server;
4
5
use Exception;
6
use GuzzleHttp\Client as GuzzleHttpClient;
7
use GuzzleHttp\Exception\BadResponseException;
8
use InvalidArgumentException;
9
use League\OAuth1\Client\Credentials\ClientCredentials;
10
use League\OAuth1\Client\Credentials\TokenCredentials;
11
use League\OAuth1\Client\Server\Server;
12
use League\OAuth1\Client\Signature\SignatureInterface;
13
14
class Xero extends Server
15
{
16
    /**
17
     * @var string
18
     */
19
    protected $responseType = 'xml';
20
21
    /**
22
     * @var bool
23
     */
24
    protected $usePartnerApi = false;
25
26
    /**
27
     * @var array
28
     */
29
    protected $httpClientOptions = [];
30
31
    /**
32
     * @var array
33
     */
34
    protected $lastTokenCredentialsResponse;
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function __construct($clientCredentials, SignatureInterface $signature = null)
40
    {
41
        if (is_array($clientCredentials)) {
42
            $this->parseConfiguration($clientCredentials);
43
44
            $clientCredentials = $this->createClientCredentials($clientCredentials);
45
46
            if (!$signature && $clientCredentials instanceof RsaClientCredentials) {
47
                $signature = new RsaSha1Signature($clientCredentials);
48
            }
49
        }
50
51
        parent::__construct($clientCredentials, $signature);
52
    }
53
54
    /**
55
     * Sets whether the Xero partner API should be used.
56
     *
57
     * @param bool $enable
58
     *
59
     * @return self
60
     */
61
    public function usePartnerApi($enable = true)
62
    {
63
        $this->usePartnerApi = $enable;
64
65
        return $this;
66
    }
67
68
    /**
69
     * Checks if the Xero partner API is used.
70
     *
71
     * @return bool
72
     */
73
    public function getUsePartnerApi()
74
    {
75
        return $this->usePartnerApi;
76
    }
77
78
    /**
79
     * Creates a Guzzle HTTP client for the given URL.
80
     *
81
     * @return GuzzleHttpClient
82
     */
83
    public function createHttpClient()
84
    {
85
        return new GuzzleHttpClient($this->httpClientOptions);
86
    }
87
88
    public function urlTemporaryCredentials()
89
    {
90
        if ($this->usePartnerApi) {
91
            return 'https://api-partner.network.xero.com/oauth/RequestToken';
92
        }
93
94
        return 'https://api.xero.com/oauth/RequestToken';
95
    }
96
97
    public function urlAuthorization()
98
    {
99
        return 'https://api.xero.com/oauth/Authorize';
100
    }
101
102
    public function urlTokenCredentials()
103
    {
104
        if ($this->usePartnerApi) {
105
            return 'https://api-partner.network.xero.com/oauth/AccessToken';
106
        }
107
108
        return 'https://api.xero.com/oauth/AccessToken';
109
    }
110
111
    public function urlUserDetails()
112
    {
113
        return $this->notSupportedByXero();
114
    }
115
116
    public function userDetails($data, TokenCredentials $tokenCredentials)
117
    {
118
        return $this->notSupportedByXero();
119
    }
120
121
    public function userUid($data, TokenCredentials $tokenCredentials)
122
    {
123
        return $this->notSupportedByXero();
124
    }
125
126
    public function userEmail($data, TokenCredentials $tokenCredentials)
127
    {
128
        return $this->notSupportedByXero();
129
    }
130
131
    public function userScreenName($data, TokenCredentials $tokenCredentials)
132
    {
133
        return $this->notSupportedByXero();
134
    }
135
136
    /**
137
     * Gets the response of the last access token call. This might
138
     * be useful for partner applications to retrieve additional
139
     * OAuth parameters passed in by Xero.
140
     *
141
     * @return array|null
142
     */
143
    public function getLastTokenCredentialsResponse()
144
    {
145
        return $this->lastTokenCredentialsResponse;
146
    }
147
148
    /**
149
     * Refreshes an access token. Can be used by partner applications.
150
     *
151
     * @param TokenCredentials $tokenCredentials
152
     * @param string           $sessionHandle    Xero session handle
153
     *
154
     * @throws League\OAuth1\Client\Credentials\CredentialsException when the access token cannot be refreshed.
155
     *
156
     * @return TokenCredentials
157
     */
158
    public function refreshToken(TokenCredentials $tokenCredentials, $sessionHandle)
159
    {
160
        $client = $this->createHttpClient();
161
        $url = $this->urlTokenCredentials();
162
163
        $parameters = [
164
            'oauth_session_handle' => $sessionHandle,
165
        ];
166
167
        $headers = $this->getHeaders($tokenCredentials, 'POST', $url, $parameters);
168
169
        try {
170
            $response = $client->post($url, [
171
                'headers' => $headers,
172
                'form_params' => $parameters,
173
            ]);
174
        } catch (BadResponseException $e) {
175
            $this->handleTokenCredentialsBadResponse($e);
176
        }
177
178
        return $this->createTokenCredentials((string) $response->getBody());
179
    }
180
181
    protected function notSupportedByXero()
182
    {
183
        throw new Exception("Xero's API does not support retrieving the current user. Please see https://xero.uservoice.com/forums/5528-xero-accounting-api/suggestions/5688571-expose-which-user-connected-the-organization-via-o");
184
    }
185
186
    /**
187
     * Parse configuration array to set attributes.
188
     *
189
     * @param array $configuration
190
     */
191
    private function parseConfiguration(array $configuration = array())
192
    {
193
        $configToPropertyMap = array(
194
            'partner' => 'usePartnerApi',
195
            'http_client' => 'httpClientOptions',
196
        );
197
        foreach ($configToPropertyMap as $config => $property) {
198
            if (isset($configuration[$config])) {
199
                $this->$property = $configuration[$config];
200
            }
201
        }
202
    }
203
204
    /**
205
     * Creates a client credentials instance from an array of credentials.
206
     *
207
     * @param array $clientCredentials
208
     *
209
     * @return ClientCredentials
210
     */
211
    protected function createClientCredentials(array $clientCredentials)
212
    {
213
        $keys = array('identifier', 'secret');
214
215
        foreach ($keys as $key) {
216
            if (!isset($clientCredentials[$key])) {
217
                throw new InvalidArgumentException("Missing client credentials key [$key] from options.");
218
            }
219
        }
220
221
        if (isset($clientCredentials['rsa_private_key']) && isset($clientCredentials['rsa_public_key'])) {
222
            $_clientCredentials = new RsaClientCredentials();
223
            $_clientCredentials->setRsaPrivateKey($clientCredentials['rsa_private_key']);
224
            $_clientCredentials->setRsaPublicKey($clientCredentials['rsa_public_key']);
225
        } else {
226
            $_clientCredentials = new ClientCredentials();
227
        }
228
229
        $_clientCredentials->setIdentifier($clientCredentials['identifier']);
230
        $_clientCredentials->setSecret($clientCredentials['secret']);
231
232
        if (isset($clientCredentials['callback_uri'])) {
233
            $_clientCredentials->setCallbackUri($clientCredentials['callback_uri']);
234
        }
235
236
        return $_clientCredentials;
237
    }
238
239
    /**
240
     * Creates token credentials from the body response.
241
     *
242
     * @param string $body
243
     *
244
     * @return TokenCredentials
245
     */
246
    protected function createTokenCredentials($body)
247
    {
248
        parse_str($body, $data);
249
        $this->lastTokenCredentialsResponse = $data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $data can be null. However, the property $lastTokenCredentialsResponse is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
250
251
        return parent::createTokenCredentials($body);
252
    }
253
}
254