11<?php
22namespace Bexio ;
33
4+ use Jumbojett \OpenIDConnectClient ;
5+
46abstract class AbstractClient
57{
8+ const PROVIDER_URL = 'https://idp.bexio.com ' ;
9+ const API_URL = 'https://api.bexio.com ' ;
10+ const API_DEFAULT_VERSION = '2.0 ' ;
11+
612 const METHOD_GET = 'GET ' ;
713 const METHOD_POST = 'POST ' ;
814 const METHOD_PUT = 'PUT ' ;
915 const METHOD_DELETE = 'DELETE ' ;
1016 const METHOD_PATCH = 'PATCH ' ;
1117
12- abstract protected function request (string $ path = '' , string $ method = self ::METHOD_GET , array $ data = [], array $ queryParams = []);
18+ private array $ config ;
19+ private string $ accessToken ;
20+ private string $ refreshToken ;
21+
22+ /**
23+ * Client constructor.
24+ *
25+ * @param string $clientId
26+ * @param string $clientSecret
27+ * @param string|null $redirectUrl
28+ */
29+ public function __construct (string $ clientId , string $ clientSecret , string $ redirectUrl = null )
30+ {
31+ $ this ->config = [
32+ 'clientId ' => $ clientId ,
33+ 'clientSecret ' => $ clientSecret ,
34+ 'redirectUrl ' => $ redirectUrl ,
35+ ];
36+ }
37+
38+ public function setClientId ($ clientId )
39+ {
40+ $ this ->config ['clientId ' ] = $ clientId ;
41+ }
42+
43+ public function getClientId ()
44+ {
45+ return $ this ->config ['clientId ' ];
46+ }
47+
48+ public function setClientSecret ($ clientId )
49+ {
50+ $ this ->config ['clientSecret ' ] = $ clientId ;
51+ }
52+
53+ public function getClientSecret ()
54+ {
55+ return $ this ->config ['clientSecret ' ];
56+ }
57+
58+ public function setRedirectUrl ($ redirectUrl )
59+ {
60+ $ this ->config ['redirectUrl ' ] = $ redirectUrl ;
61+ }
62+
63+ public function getRedirectUrl ()
64+ {
65+ return $ this ->config ['redirectUrl ' ];
66+ }
67+
68+ public function setAccessToken (string $ accessToken )
69+ {
70+ $ this ->accessToken = $ accessToken ;
71+ }
72+
73+ public function getAccessToken ()
74+ {
75+ return $ this ->accessToken ;
76+ }
77+
78+ public function setRefreshToken (string $ refreshToken )
79+ {
80+ $ this ->refreshToken = $ refreshToken ;
81+ }
82+
83+ public function getRefreshToken ()
84+ {
85+ return $ this ->refreshToken ;
86+ }
87+
88+ public function persistTokens (string $ tokensFile ): bool
89+ {
90+ return false !== file_put_contents ($ tokensFile , json_encode ([
91+ 'accessToken ' => $ this ->getAccessToken (),
92+ 'refreshToken ' => $ this ->getRefreshToken ()
93+ ]));
94+ }
95+
96+ public function loadTokens (string $ tokensFile )
97+ {
98+ if (!file_exists ($ tokensFile )) {
99+ throw new \Exception ('Tokens file not found: ' . $ tokensFile );
100+ }
101+ $ tokens = json_decode (file_get_contents ($ tokensFile ));
102+
103+ $ this ->setAccessToken ($ tokens ->accessToken );
104+ $ this ->setRefreshToken ($ tokens ->refreshToken );
105+
106+ // Refresh access token if it is expired
107+ if ($ this ->isAccessTokenExpired ()) {
108+ $ this ->refreshToken ();
109+ $ this ->persistTokens ($ tokensFile );
110+ }
111+ }
112+
113+ public function getOpenIDConnectClient (): OpenIDConnectClient
114+ {
115+ $ oidc = new OpenIDConnectClient (
116+ self ::PROVIDER_URL ,
117+ $ this ->getClientId (),
118+ $ this ->getClientSecret ()
119+ );
120+ $ oidc ->setAccessToken ($ this ->accessToken );
121+ return $ oidc ;
122+ }
123+
124+ public function authenticate ($ scopes )
125+ {
126+ if (!is_array ($ scopes )) {
127+ $ scopes = explode (' ' , $ scopes );
128+ }
129+ $ oidc = $ this ->getOpenIDConnectClient ();
130+ $ oidc ->setRedirectURL ($ this ->getRedirectUrl ());
131+ $ oidc ->addScope ($ scopes );
132+ $ oidc ->authenticate ();
133+
134+ $ this ->setAccessToken ($ oidc ->getAccessToken ());
135+ $ this ->setRefreshToken ($ oidc ->getRefreshToken ());
136+ }
137+
138+ public function isAccessTokenExpired ($ gracePeriod = 30 ): bool
139+ {
140+ if (!$ this ->accessToken ) {
141+ return true ;
142+ }
143+ $ payload = $ this ->getOpenIDConnectClient ()->getAccessTokenPayload ();
144+ $ expiry = $ payload ->exp ?? 0 ;
145+ return time () > ($ expiry - $ gracePeriod );
146+ }
147+
148+ public function refreshToken ()
149+ {
150+ $ oidc = $ this ->getOpenIDConnectClient ();
151+ $ oidc ->refreshToken ($ this ->getRefreshToken ());
152+ $ this ->setAccessToken ($ oidc ->getAccessToken ());
153+ $ this ->setRefreshToken ($ oidc ->getRefreshToken ());
154+ }
155+
156+ public function getFullApiUrl (string $ path = '' )
157+ {
158+ // prefix path with default API version if there was no version provided
159+ return implode ('/ ' , array_filter ([
160+ self ::API_URL ,
161+ 1 === preg_match ('/\d\.\d\// ' , $ path ) ? '' : self ::API_DEFAULT_VERSION ,
162+ $ path
163+ ]));
164+ }
13165
14166 public function get (string $ path , array $ queryParams = [])
15167 {
@@ -35,4 +187,11 @@ public function patch(string $path, array $data = [], array $queryParams = [])
35187 {
36188 return $ this ->request ($ path , self ::METHOD_PATCH , $ data , $ queryParams );
37189 }
190+
191+ abstract protected function request (
192+ string $ path = '' ,
193+ string $ method = self ::METHOD_GET ,
194+ array $ data = [],
195+ array $ queryParams = []
196+ );
38197}
0 commit comments