Completed
Push — master ( 900936...3549a9 )
by Dmitriy
12s
created

OAuthClient   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 12
Bugs 3 Features 2
Metric Value
wmc 18
c 12
b 3
f 2
lcom 1
cbo 6
dl 0
loc 175
ccs 56
cts 56
cp 1
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setClientId() 0 6 1
A setClientSecret() 0 6 1
A getClientId() 0 4 1
A getClientSecret() 0 4 1
A getAuthUrl() 0 9 2
A authRedirect() 0 6 2
B requestAccessToken() 0 56 9
1
<?php
2
/**
3
 * Yandex PHP Library
4
 *
5
 * @copyright NIX Solutions Ltd.
6
 * @link https://github.com/nixsolutions/yandex-php-library
7
 */
8
9
/**
10
 * @namespace
11
 */
12
namespace Yandex\OAuth;
13
14
use GuzzleHttp\Client;
15
use GuzzleHttp\Exception\ClientException;
16
use GuzzleHttp\Exception\RequestException;
17
use Yandex\Common\AbstractServiceClient;
18
use Yandex\OAuth\Exception\AuthRequestException;
19
use Yandex\OAuth\Exception\AuthResponseException;
20
21
/**
22
 * Class OAuthClient implements Yandex OAuth protocol
23
 *
24
 * @category Yandex
25
 * @package  OAuth
26
 *
27
 * @author   Eugene Zabolotniy <[email protected]>
28
 * @created  29.08.13 12:07
29
 */
30
class OAuthClient extends AbstractServiceClient
31
{
32
    /*
33
     * Authentication types constants
34
     *
35
     * The "code" type means that the application will use an intermediate code to obtain an access token.
36
     * The "token" type will result a user is redirected back to the application with an access token in a URL
37
     */
38
    const CODE_AUTH_TYPE = 'code';
39
    const TOKEN_AUTH_TYPE = 'token';
40
41
    /**
42
     * @var string
43
     */
44
    private $clientId = '';
45
46
    /**
47
     * @var string
48
     */
49
    private $clientSecret = '';
50
51
    /**
52
     * @var string
53
     */
54
    protected $serviceDomain = 'oauth.yandex.ru';
55
56
    /**
57
     * @param string $clientId
58
     * @param string $clientSecret
59
     */
60 24
    public function __construct($clientId = '', $clientSecret = '')
61
    {
62 24
        $this->setClientId($clientId);
63 24
        $this->setClientSecret($clientSecret);
64 24
    }
65
66
    /**
67
     * @param string $clientId
68
     *
69
     * @return self
70
     */
71 24
    public function setClientId($clientId)
72
    {
73 24
        $this->clientId = $clientId;
74
75 24
        return $this;
76
    }
77
78
    /**
79
     * @return string
80
     */
81 2
    public function getClientId()
82
    {
83 2
        return $this->clientId;
84
    }
85
86
    /**
87
     * @param string $clientSecret
88
     *
89
     * @return self
90
     */
91 24
    public function setClientSecret($clientSecret)
92
    {
93 24
        $this->clientSecret = $clientSecret;
94
95 24
        return $this;
96
    }
97
98
    /**
99
     * @return string
100
     */
101 2
    public function getClientSecret()
102
    {
103 2
        return $this->clientSecret;
104
    }
105
106
    /**
107
     * @param string $type
108
     * @param string $state optional string
109
     *
110
     * @return string
111
     */
112 2
    public function getAuthUrl($type = self::CODE_AUTH_TYPE, $state = null)
113
    {
114 2
        $url = $this->getServiceUrl('authorize') . '?response_type=' . $type . '&client_id=' . $this->clientId;
115 2
        if ($state) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $state of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
116 1
            $url .= '&state=' . $state;
117 1
        }
118
119 2
        return $url;
120
    }
121
122
    /**
123
     * Sends a redirect to the Yandex authentication page.
124
     *
125
     * @param bool   $exit  indicates whether to stop the PHP script immediately or not
126
     * @param string $type  a type of the authentication procedure
127
     * @param string $state optional string
128
     * @return bool|void
129
     */
130 1
    public function authRedirect($exit = true, $type = self::CODE_AUTH_TYPE, $state = null)
131
    {
132 1
        header('Location: ' . $this->getAuthUrl($type, $state));
133
134 1
        return $exit ? exit() : true;
135
    }
136
137
    /**
138
     * Exchanges a temporary code for an access token.
139
     *
140
     * @param $code
141
     *
142
     * @throws AuthRequestException on a known request error
143
     * @throws AuthResponseException on a response format error
144
     * @throws RequestException on an unknown request error
145
     *
146
     * @return self
147
     */
148 6
    public function requestAccessToken($code)
149
    {
150 6
        $client = $this->getClient();
151
152
        try {
153 6
            $response = $client->request(
154 6
                'POST',
155 6
                '/token',
156
                [
157
                    'auth' => [
158 6
                        $this->clientId,
159 6
                        $this->clientSecret
160 6
                    ],
161
                    'form_params' => [
162 6
                        'grant_type'    => 'authorization_code',
163 6
                        'code'          => $code,
164 6
                        'client_id'     => $this->clientId,
165 6
                        'client_secret' => $this->clientSecret
166 6
                    ]
167 6
                ]
168 6
            );
169 6
        } catch (ClientException $ex) {
170 2
            $result = $this->getDecodedBody($ex->getResponse()->getBody());
171
172 2
            if (is_array($result) && isset($result['error'])) {
173
                // handle a service error message
174 1
                $message = 'Service responsed with error code "' . $result['error'] . '".';
175
176 1
                if (isset($result['error_description']) && $result['error_description']) {
177 1
                    $message .= ' Description "' . $result['error_description'] . '".';
178 1
                }
179 1
                throw new AuthRequestException($message, 0, $ex);
180
            }
181
182
            // unknown error. not parsed error
183 1
            throw $ex;
184
        }
185
186
        try {
187 4
            $result = $this->getDecodedBody($response->getBody());
188 4
        } catch (\RuntimeException $ex) {
189 1
            throw new AuthResponseException('Server response can\'t be parsed', 0, $ex);
190
        }
191
192 3
        if (!is_array($result)) {
193 1
            throw new AuthResponseException('Server response has unknown format');
194
        }
195
196 2
        if (!isset($result['access_token'])) {
197 1
            throw new AuthResponseException('Server response doesn\'t contain access token');
198
        }
199
200 1
        $this->setAccessToken($result['access_token']);
201
202 1
        return $this;
203
    }
204
}
205