Passed
Push — master ( 5e1c69...957702 )
by Artem
01:39
created

ApiClient::createNewAccessTokenByPhone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Shoman4eg\Nalog;
5
6
use Http\Client\HttpClient;
7
use JsonException;
8
use Psr\Http\Client\ClientExceptionInterface;
9
use Psr\Http\Client\ClientInterface;
10
use Shoman4eg\Nalog\Http\AuthenticationPlugin;
11
use Shoman4eg\Nalog\Http\Authenticator;
12
use Shoman4eg\Nalog\Http\ClientConfigurator;
13
use Shoman4eg\Nalog\Model\User\UserType;
14
use Shoman4eg\Nalog\Service\Generator\DeviceIdGenerator;
15
use Shoman4eg\Nalog\Util\JSON;
16
17
/**
18
 * @author Artem Dubinin <[email protected]>
19
 */
20
class ApiClient
21
{
22
    private RequestBuilder $requestBuilder;
23
    private ClientConfigurator $clientConfigurator;
24
    private Authenticator $authenticator;
25
    private ?UserType $profile;
26
27
    /**
28
     * The constructor accepts already configured HTTP clients.
29
     * Use the configure method to pass a configuration to the Client and create an HTTP Client.
30
     */
31
    public function __construct(
32
        ClientConfigurator $clientConfigurator,
33
        RequestBuilder $requestBuilder = null,
34
        DeviceIdGenerator $deviceIdGenerator = null
35
    ) {
36
        $this->clientConfigurator = $clientConfigurator;
37
        $this->requestBuilder = $requestBuilder ?: new RequestBuilder();
38
        $deviceIdGenerator ??= new DeviceIdGenerator();
39
        $this->authenticator = new Authenticator(
40
            $this->requestBuilder,
41
            $this->clientConfigurator->createConfiguredClient(),
42
            $deviceIdGenerator->generate()
43
        );
44
    }
45
46
    public static function create(): self
47
    {
48
        $clientConfigurator = new ClientConfigurator();
49
50
        return new self($clientConfigurator);
51
    }
52
53
    public static function createWithEndpoint(string $endpoint): self
54
    {
55
        $clientConfigurator = new ClientConfigurator();
56
        $clientConfigurator->setEndpoint($endpoint);
57
58
        return new self($clientConfigurator);
59
    }
60
61
    public static function createWithCustomClient(ClientInterface $client): self
62
    {
63
        return new self(new ClientConfigurator($client));
64
    }
65
66
    /**
67
     * Warning, this will remove the current access token.
68
     *
69
     * @throws ClientExceptionInterface
70
     * @throws JsonException
71
     * @throws Exception\DomainException
72
     */
73
    public function createNewAccessToken(string $username, string $password): ?string
74
    {
75
        $this->clientConfigurator->removePlugin(AuthenticationPlugin::class);
76
77
        return $this->authenticator->createAccessToken($username, $password);
78
    }
79
80
    /**
81
     * Used as the first step, before createPhoneChallenge()
82
     * 
83
     * Request the verification code in the SMS-message for authorization by phone number.
84
     * Returns the call token and its lifetime.
85
     * 
86
     * Save the phone number and call token. When the user specifies the code from the SMS,
87
     * pass them to createNewAccessTokenByPhone() along with the code from the SMS
88
     *
89
     * Remember that there are restrictions on sending SMS. The value seems to be dynamic,
90
     * approximately 1 message every 1-2 minutes.
91
     * The restriction is removed after a successful createNewAccessTokenByPhone()
92
     * 
93
     * @throws ClientExceptionInterface
94
     * @throws JsonException
95
     * @throws Exception\DomainException
96
     * @return array{challengeToken: string, expireDate: string, expireIn: int}
97
     */
98
    public static function createPhoneChallenge(string $phone): array
99
    {
100
        $client = self::create();
101
        $client->clientConfigurator->setVersion('v2');
102
        $client->clientConfigurator->removePlugin(AuthenticationPlugin::class);
103
104
        return $client->authenticator->createPhoneChallenge($phone);
105
    }
106
107
    /**
108
     * Used as the second step, after createPhoneChallenge()
109
     * Warning, this will remove the current access token.
110
     *
111
     * @throws ClientExceptionInterface
112
     * @throws JsonException
113
     * @throws Exception\DomainException
114
     */
115
    public function createNewAccessTokenByPhone(string $phone, string $challengeToken, string $verificationCode): ?string
116
    {
117
        $this->clientConfigurator->removePlugin(AuthenticationPlugin::class);
118
119
        return $this->authenticator->createAccessTokenByPhone($phone, $challengeToken, $verificationCode);
120
    }
121
    /**
122
     * Authenticate the client with an access token. This should be the full access token object with
123
     * refresh token and expirery timestamps.
124
     *
125
     * ```php
126
     *   $accessToken = $client->createNewAccessToken('inn', 'password');
127
     *   $client->authenticate($accessToken);
128
     *```
129
     *
130
     * @throws JsonException
131
     */
132
    public function authenticate(string $accessToken): void
133
    {
134
        $this->clientConfigurator->removePlugin(AuthenticationPlugin::class);
135
        $this->clientConfigurator->appendPlugin(new AuthenticationPlugin($this->authenticator, $accessToken));
136
        if (($token = JSON::decode($accessToken)) && array_key_exists('profile', $token)) {
137
            $this->profile = UserType::createFromArray($token['profile']);
138
        }
139
        $this->authenticator->setAccessToken($accessToken);
140
    }
141
142
    /**
143
     * The access token may have been refreshed during the requests. Use this function to
144
     * get back the (possibly) refreshed access token.
145
     */
146
    public function getAccessToken(): ?string
147
    {
148
        return $this->authenticator->getAccessToken();
149
    }
150
151
    public function income(): Api\Income
152
    {
153
        return new Api\Income($this->getHttpClient(), $this->requestBuilder);
154
    }
155
156
    public function receipt(): Api\Receipt
157
    {
158
        return new Api\Receipt(
159
            $this->getHttpClient(),
160
            $this->requestBuilder,
161
            $this->profile ?? $this->user()->get(),
162
            (string)$this->clientConfigurator->getEndpoint()
163
        );
164
    }
165
166
    public function user(): Api\User
167
    {
168
        return new Api\User($this->getHttpClient(), $this->requestBuilder);
169
    }
170
171
    public function paymentType(): Api\PaymentType
172
    {
173
        return new Api\PaymentType($this->getHttpClient(), $this->requestBuilder);
174
    }
175
176
    private function getHttpClient(): HttpClient
177
    {
178
        return $this->clientConfigurator->createConfiguredClient();
179
    }
180
}
181