44
55namespace CasParser \Core ;
66
7+ use CasParser \Core \Contracts \BasePage ;
8+ use CasParser \Core \Contracts \BaseStream ;
9+ use CasParser \Core \Conversion \Contracts \Converter ;
10+ use CasParser \Core \Conversion \Contracts \ConverterSource ;
711use CasParser \Core \Errors \APIStatusError ;
812use CasParser \RequestOptions ;
913use Http \Discovery \Psr17FactoryDiscovery ;
1620use Psr \Http \Message \UriFactoryInterface ;
1721use Psr \Http \Message \UriInterface ;
1822
23+ /**
24+ * @phpstan-type normalized_request = array{
25+ * method: string,
26+ * path: string,
27+ * query: array<string, mixed>,
28+ * headers: array<string, string|null|list<string>>,
29+ * body: mixed,
30+ * }
31+ */
1932class BaseClient
2033{
2134 protected UriInterface $ baseUrl ;
@@ -48,37 +61,56 @@ public function __construct(
4861 * @param string|list<mixed> $path
4962 * @param array<string, mixed> $query
5063 * @param array<string, mixed> $headers
64+ * @param class-string<BasePage<mixed>> $page
65+ * @param class-string<BaseStream<mixed>> $stream
5166 */
5267 public function request (
5368 string $ method ,
5469 string |array $ path ,
5570 array $ query = [],
5671 array $ headers = [],
5772 mixed $ body = null ,
73+ string |Converter |ConverterSource |null $ convert = null ,
74+ ?string $ page = null ,
75+ ?string $ stream = null ,
5876 mixed $ options = [],
5977 ): mixed {
6078 // @phpstan-ignore-next-line
61- [$ req , $ opts ] = $ this ->buildRequest (method: $ method , path: $ path , query: $ query , headers: $ headers , opts: $ options );
79+ [$ req , $ opts ] = $ this ->buildRequest (method: $ method , path: $ path , query: $ query , headers: $ headers , body: $ body , opts: $ options );
80+ ['method ' => $ method , 'path ' => $ uri , 'headers ' => $ headers ] = $ req ;
81+
82+ $ req = $ this ->requestFactory ->createRequest ($ method , uri: $ uri );
83+ $ req = Util::withSetHeaders ($ req , headers: $ headers );
6284
6385 // @phpstan-ignore-next-line
6486 $ rsp = $ this ->sendRequest ($ req , data: $ body , opts: $ opts , redirectCount: 0 , retryCount: 0 );
65- if (204 == $ rsp ->getStatusCode ()) {
66- return null ; // Handle 204 No Content
87+
88+ $ decoded = Util::decodeContent ($ rsp );
89+
90+ if (!is_null ($ stream )) {
91+ return new $ stream (
92+ convert: $ convert ,
93+ request: $ req ,
94+ response: $ rsp ,
95+ stream: $ decoded
96+ );
6797 }
6898
69- return Util::decodeContent ($ rsp );
70- }
99+ if (!is_null ($ page )) {
100+ return new $ page (
101+ convert: $ convert ,
102+ client: $ this ,
103+ request: $ req ,
104+ options: $ opts ,
105+ data: $ decoded ,
106+ );
107+ }
71108
72- /**
73- * @template Item
74- * @template T of Pagination\AbstractPage<Item>
75- *
76- * @param T $page
77- */
78- public function requestApiList (object $ page , RequestOptions $ options ): ResponseInterface
79- {
80- // @phpstan-ignore-next-line
81- return null ;
109+ if (!is_null ($ convert )) {
110+ return Conversion::coerce ($ convert , value: $ decoded );
111+ }
112+
113+ return $ decoded ;
82114 }
83115
84116 /** @return array<string, string> */
@@ -91,24 +123,25 @@ protected function authHeaders(): array
91123 * @param string|list<string> $path
92124 * @param array<string, mixed> $query
93125 * @param array<string, string|int|list<string|int>|null> $headers
94- * @param array{
126+ * @param RequestOptions| array{
95127 * timeout?: float|null,
96128 * maxRetries?: int|null,
97129 * initialRetryDelay?: float|null,
98130 * maxRetryDelay?: float|null,
99131 * extraHeaders?: list<string>|null,
100132 * extraQueryParams?: list<string>|null,
101133 * extraBodyParams?: list<string>|null,
102- * }|RequestOptions| null $opts
134+ * }|null $opts
103135 *
104- * @return array{RequestInterface , RequestOptions}
136+ * @return array{normalized_request , RequestOptions}
105137 */
106138 protected function buildRequest (
107139 string $ method ,
108140 string |array $ path ,
109141 array $ query ,
110142 array $ headers ,
111- array |RequestOptions |null $ opts ,
143+ mixed $ body ,
144+ RequestOptions |array |null $ opts ,
112145 ): array {
113146 $ opts = [...$ this ->options ->__serialize (), ...RequestOptions::parse ($ opts )->__serialize ()];
114147 $ options = new RequestOptions (...$ opts );
@@ -117,16 +150,15 @@ protected function buildRequest(
117150
118151 /** @var array<string, mixed> $mergedQuery */
119152 $ mergedQuery = array_merge_recursive ($ query , $ options ->extraQueryParams );
120- $ uri = Util::joinUri ($ this ->baseUrl , path: $ parsedPath , query: $ mergedQuery );
153+ $ uri = Util::joinUri ($ this ->baseUrl , path: $ parsedPath , query: $ mergedQuery )-> __toString () ;
121154
122- /** @var array<string, string | list<string>> $mergedHeaders */
155+ /** @var array<string, string| list<string>|null > $mergedHeaders */
123156 $ mergedHeaders = [...$ this ->headers ,
124157 ...$ this ->authHeaders (),
125158 ...$ headers ,
126159 ...$ options ->extraHeaders , ];
127160
128- $ req = $ this ->requestFactory ->createRequest (strtoupper ($ method ), uri: $ uri );
129- $ req = Util::withSetHeaders ($ req , headers: $ mergedHeaders );
161+ $ req = ['method ' => strtoupper ($ method ), 'path ' => $ uri , 'query ' => $ mergedQuery , 'headers ' => $ mergedHeaders , 'body ' => $ body ];
130162
131163 return [$ req , $ options ];
132164 }
0 commit comments