22
33namespace Redmine \Api ;
44
5+ use Closure ;
6+ use InvalidArgumentException ;
57use Redmine \Api ;
68use Redmine \Client \Client ;
79use Redmine \Exception ;
810use Redmine \Exception \SerializerException ;
11+ use Redmine \Http \HttpClient ;
12+ use Redmine \Http \Response ;
913use Redmine \Serializer \JsonSerializer ;
1014use Redmine \Serializer \PathSerializer ;
1115use Redmine \Serializer \XmlSerializer ;
@@ -23,9 +27,52 @@ abstract class AbstractApi implements Api
2327 */
2428 protected $ client ;
2529
26- public function __construct (Client $ client )
30+ /**
31+ * @var HttpClient
32+ */
33+ private $ httpClient ;
34+
35+ /**
36+ * @var Response
37+ */
38+ private $ lastResponse ;
39+
40+ /**
41+ * @param Client|HttpClient $client
42+ */
43+ public function __construct ($ client )
2744 {
28- $ this ->client = $ client ;
45+ if (! is_object ($ client ) || (! $ client instanceof Client && ! $ client instanceof HttpClient)) {
46+ throw new InvalidArgumentException (sprintf (
47+ '%s(): Argument #1 ($client) must be of type %s or %s, `%s` given ' ,
48+ __METHOD__ ,
49+ Client::class,
50+ HttpClient::class,
51+ (is_object ($ client )) ? get_class ($ client ) : gettype ($ client )
52+ ));
53+ }
54+
55+ if ($ client instanceof Client) {
56+ $ this ->client = $ client ;
57+ }
58+
59+ $ httpClient = $ client ;
60+
61+ if (! $ httpClient instanceof HttpClient) {
62+ $ httpClient = $ this ->handleClient ($ client );
63+ }
64+
65+ $ this ->httpClient = $ httpClient ;
66+ }
67+
68+ final protected function getHttpClient (): HttpClient
69+ {
70+ return $ this ->httpClient ;
71+ }
72+
73+ final protected function getLastResponse (): Response
74+ {
75+ return $ this ->lastResponse !== null ? $ this ->lastResponse : $ this ->createResponse (0 , '' , '' );
2976 }
3077
3178 /**
@@ -40,7 +87,13 @@ public function lastCallFailed()
4087 {
4188 @trigger_error ('` ' . __METHOD__ . '()` is deprecated since v2.1.0, use \Redmine\Client\Client::getLastResponseStatusCode() instead. ' , E_USER_DEPRECATED );
4289
43- $ code = $ this ->client ->getLastResponseStatusCode ();
90+ if ($ this ->lastResponse !== null ) {
91+ $ code = $ this ->lastResponse ->getStatusCode ();
92+ } elseif ($ this ->client !== null ) {
93+ $ code = $ this ->client ->getLastResponseStatusCode ();
94+ } else {
95+ $ code = 0 ;
96+ }
4497
4598 return 200 !== $ code && 201 !== $ code ;
4699 }
@@ -55,10 +108,10 @@ public function lastCallFailed()
55108 */
56109 protected function get ($ path , $ decodeIfJson = true )
57110 {
58- $ this ->client -> requestGet ( strval ($ path ));
111+ $ this ->lastResponse = $ this -> getHttpClient ()-> request ( ' GET ' , strval ($ path ));
59112
60- $ body = $ this ->client -> getLastResponseBody ();
61- $ contentType = $ this ->client -> getLastResponseContentType ();
113+ $ body = $ this ->lastResponse -> getBody ();
114+ $ contentType = $ this ->lastResponse -> getContentType ();
62115
63116 // if response is XML, return a SimpleXMLElement object
64117 if ('' !== $ body && 0 === strpos ($ contentType , 'application/xml ' )) {
@@ -82,16 +135,17 @@ protected function get($path, $decodeIfJson = true)
82135 * @param string $path
83136 * @param string $data
84137 *
85- * @return string|false
138+ * @return string|SimpleXMLElement| false
86139 */
87140 protected function post ($ path , $ data )
88141 {
89- $ this ->client -> requestPost ( $ path , $ data );
142+ $ this ->lastResponse = $ this -> getHttpClient ()-> request ( ' POST ' , strval ( $ path) , $ data );
90143
91- $ body = $ this ->client ->getLastResponseBody ();
144+ $ body = $ this ->lastResponse ->getBody ();
145+ $ contentType = $ this ->lastResponse ->getContentType ();
92146
93147 // if response is XML, return a SimpleXMLElement object
94- if ('' !== $ body && 0 === strpos ($ this -> client -> getLastResponseContentType () , 'application/xml ' )) {
148+ if ('' !== $ body && 0 === strpos ($ contentType , 'application/xml ' )) {
95149 return new SimpleXMLElement ($ body );
96150 }
97151
@@ -104,16 +158,17 @@ protected function post($path, $data)
104158 * @param string $path
105159 * @param string $data
106160 *
107- * @return string|false
161+ * @return string|SimpleXMLElement
108162 */
109163 protected function put ($ path , $ data )
110164 {
111- $ this ->client -> requestPut ( $ path , $ data );
165+ $ this ->lastResponse = $ this -> getHttpClient ()-> request ( ' PUT ' , strval ( $ path) , $ data );
112166
113- $ body = $ this ->client ->getLastResponseBody ();
167+ $ body = $ this ->lastResponse ->getBody ();
168+ $ contentType = $ this ->lastResponse ->getContentType ();
114169
115170 // if response is XML, return a SimpleXMLElement object
116- if ('' !== $ body && 0 === strpos ($ this -> client -> getLastResponseContentType () , 'application/xml ' )) {
171+ if ('' !== $ body && 0 === strpos ($ contentType , 'application/xml ' )) {
117172 return new SimpleXMLElement ($ body );
118173 }
119174
@@ -125,13 +180,13 @@ protected function put($path, $data)
125180 *
126181 * @param string $path
127182 *
128- * @return false|SimpleXMLElement| string
183+ * @return string
129184 */
130185 protected function delete ($ path )
131186 {
132- $ this ->client -> requestDelete ( $ path );
187+ $ this ->lastResponse = $ this -> getHttpClient ()-> request ( ' DELETE ' , strval ( $ path) );
133188
134- return $ this ->client -> getLastResponseBody ();
189+ return $ this ->lastResponse -> getBody ();
135190 }
136191
137192 /**
@@ -179,7 +234,7 @@ protected function retrieveAll($endpoint, array $params = [])
179234 try {
180235 $ data = $ this ->retrieveData (strval ($ endpoint ), $ params );
181236 } catch (Exception $ e ) {
182- if ($ this ->client -> getLastResponseBody () === '' ) {
237+ if ($ this ->getLastResponse ()-> getBody () === '' ) {
183238 return false ;
184239 }
185240
@@ -203,9 +258,9 @@ protected function retrieveAll($endpoint, array $params = [])
203258 protected function retrieveData (string $ endpoint , array $ params = []): array
204259 {
205260 if (empty ($ params )) {
206- $ this ->client -> requestGet ( $ endpoint );
261+ $ this ->lastResponse = $ this -> getHttpClient ()-> request ( ' GET ' , strval ( $ endpoint) );
207262
208- return $ this ->getLastResponseBodyAsArray ( );
263+ return $ this ->getResponseAsArray ( $ this -> lastResponse );
209264 }
210265
211266 $ params = $ this ->sanitizeParams (
@@ -232,11 +287,12 @@ protected function retrieveData(string $endpoint, array $params = []): array
232287 $ params ['limit ' ] = $ _limit ;
233288 $ params ['offset ' ] = $ offset ;
234289
235- $ this ->client ->requestGet (
290+ $ this ->lastResponse = $ this ->getHttpClient ()->request (
291+ 'GET ' ,
236292 PathSerializer::create ($ endpoint , $ params )->getPath ()
237293 );
238294
239- $ newDataSet = $ this ->getLastResponseBodyAsArray ( );
295+ $ newDataSet = $ this ->getResponseAsArray ( $ this -> lastResponse );
240296
241297 $ returnData = array_merge_recursive ($ returnData , $ newDataSet );
242298
@@ -310,11 +366,10 @@ protected function attachCustomFieldXML(SimpleXMLElement $xml, array $fields)
310366 *
311367 * @throws SerializerException if response body could not be converted into array
312368 */
313- private function getLastResponseBodyAsArray ( ): array
369+ private function getResponseAsArray ( Response $ response ): array
314370 {
315- $ body = $ this ->client ->getLastResponseBody ();
316-
317- $ contentType = $ this ->client ->getLastResponseContentType ();
371+ $ body = $ response ->getBody ();
372+ $ contentType = $ response ->getContentType ();
318373 $ returnData = null ;
319374
320375 // parse XML
@@ -330,4 +385,70 @@ private function getLastResponseBodyAsArray(): array
330385
331386 return $ returnData ;
332387 }
388+
389+ private function handleClient (Client $ client ): HttpClient
390+ {
391+ $ responseFactory = Closure::fromCallable ([$ this , 'createResponse ' ]);
392+
393+ return new class ($ client , $ responseFactory ) implements HttpClient {
394+ private $ client ;
395+ private $ responseFactory ;
396+
397+ public function __construct (Client $ client , Closure $ responseFactory )
398+ {
399+ $ this ->client = $ client ;
400+ $ this ->responseFactory = $ responseFactory ;
401+ }
402+
403+ public function request (string $ method , string $ path , string $ body = '' ): Response
404+ {
405+ if ($ method === 'POST ' ) {
406+ $ this ->client ->requestPost ($ path , $ body );
407+ } elseif ($ method === 'PUT ' ) {
408+ $ this ->client ->requestPut ($ path , $ body );
409+ } elseif ($ method === 'DELETE ' ) {
410+ $ this ->client ->requestDelete ($ path );
411+ } else {
412+ $ this ->client ->requestGet ($ path );
413+ }
414+
415+ return ($ this ->responseFactory )(
416+ $ this ->client ->getLastResponseStatusCode (),
417+ $ this ->client ->getLastResponseContentType (),
418+ $ this ->client ->getLastResponseBody ()
419+ );
420+ }
421+ };
422+ }
423+
424+ private function createResponse (int $ statusCode , string $ contentType , string $ body ): Response
425+ {
426+ return new class ($ statusCode , $ contentType , $ body ) implements Response {
427+ private $ statusCode ;
428+ private $ contentType ;
429+ private $ body ;
430+
431+ public function __construct (int $ statusCode , string $ contentType , string $ body )
432+ {
433+ $ this ->statusCode = $ statusCode ;
434+ $ this ->contentType = $ contentType ;
435+ $ this ->body = $ body ;
436+ }
437+
438+ public function getStatusCode (): int
439+ {
440+ return $ this ->statusCode ;
441+ }
442+
443+ public function getContentType (): string
444+ {
445+ return $ this ->contentType ;
446+ }
447+
448+ public function getBody (): string
449+ {
450+ return $ this ->body ;
451+ }
452+ };
453+ }
333454}
0 commit comments