22
33namespace ProgrammatorDev \OpenWeatherMap \Endpoint ;
44
5- use Http \Client \Common \HttpMethodsClient ;
5+ use Http \Client \Common \Plugin \CachePlugin ;
6+ use Http \Client \Common \Plugin \LoggerPlugin ;
67use Http \Client \Exception ;
7- use ProgrammatorDev \OpenWeatherMap \Endpoint \ Util \ WithCacheInvalidationTrait ;
8+ use ProgrammatorDev \OpenWeatherMap \Config ;
89use ProgrammatorDev \OpenWeatherMap \Endpoint \Util \WithCacheTtlTrait ;
910use ProgrammatorDev \OpenWeatherMap \Entity \Error ;
1011use ProgrammatorDev \OpenWeatherMap \Exception \BadRequestException ;
1112use ProgrammatorDev \OpenWeatherMap \Exception \NotFoundException ;
1213use ProgrammatorDev \OpenWeatherMap \Exception \TooManyRequestsException ;
1314use ProgrammatorDev \OpenWeatherMap \Exception \UnauthorizedException ;
1415use ProgrammatorDev \OpenWeatherMap \Exception \UnexpectedErrorException ;
16+ use ProgrammatorDev \OpenWeatherMap \HttpClient \HttpClientBuilder ;
17+ use ProgrammatorDev \OpenWeatherMap \HttpClient \Listener \LoggerCacheListener ;
1518use ProgrammatorDev \OpenWeatherMap \HttpClient \ResponseMediator ;
1619use ProgrammatorDev \OpenWeatherMap \OpenWeatherMap ;
1720use Psr \Cache \CacheItemPoolInterface ;
18- use Psr \Cache \InvalidArgumentException ;
1921use Psr \Http \Message \ResponseInterface ;
2022use Psr \Http \Message \StreamInterface ;
2123use Psr \Http \Message \UriInterface ;
2426class AbstractEndpoint
2527{
2628 use WithCacheTtlTrait;
27- use WithCacheInvalidationTrait;
2829
29- private HttpMethodsClient $ httpClient ;
30+ private Config $ config ;
3031
31- private ? LoggerInterface $ logger ;
32+ private HttpClientBuilder $ httpClientBuilder ;
3233
3334 private ?CacheItemPoolInterface $ cache ;
3435
35- private bool $ cacheInvalidation = false ;
36-
37- protected \DateInterval |int |null $ cacheTtl = 60 * 10 ; // 10 minutes
36+ private ?LoggerInterface $ logger ;
3837
3938 protected string $ measurementSystem ;
4039
4140 protected string $ language ;
4241
42+ protected ?int $ cacheTtl = 60 * 10 ; // 10 minutes
43+
4344 public function __construct (protected OpenWeatherMap $ api )
4445 {
45- $ config = $ this ->api ->getConfig ();
46+ $ this -> config = $ this ->api ->getConfig ();
4647
47- $ this ->httpClient = $ config -> getHttpClientBuilder ()-> getHttpClient ();
48- $ this ->logger = $ config ->getLogger ();
49- $ this ->cache = $ config ->getCache ();
50- $ this ->measurementSystem = $ config ->getMeasurementSystem ();
51- $ this ->language = $ config ->getLanguage ();
48+ $ this ->httpClientBuilder = $ this -> config -> getHttpClientBuilder ();
49+ $ this ->cache = $ this -> config ->getCache ();
50+ $ this ->logger = $ this -> config ->getLogger ();
51+ $ this ->measurementSystem = $ this -> config ->getMeasurementSystem ();
52+ $ this ->language = $ this -> config ->getLanguage ();
5253 }
5354
5455 /**
@@ -58,7 +59,6 @@ public function __construct(protected OpenWeatherMap $api)
5859 * @throws TooManyRequestsException
5960 * @throws UnauthorizedException
6061 * @throws UnexpectedErrorException
61- * @throws InvalidArgumentException
6262 */
6363 protected function sendRequest (
6464 string $ method ,
@@ -68,79 +68,61 @@ protected function sendRequest(
6868 StreamInterface |string $ body = null
6969 ): array
7070 {
71- $ uri = $ this ->buildUrl ($ baseUrl , $ query );
72-
73- // If there is a cache adapter, save responses into cache
74- if ($ this ->cache !== null ) {
75- $ cacheKey = $ this ->getCacheKey ($ uri );
76-
77- // Invalidate cache to force new
78- if ($ this ->cacheInvalidation === true ) {
79- $ this ->logger ?->info('Cache invalidated ' , ['key ' => $ cacheKey ]);
80-
81- $ this ->cache ->deleteItem ($ cacheKey );
82- }
71+ $ this ->configurePlugins ();
8372
84- $ cacheItem = $ this ->cache ->getItem ($ cacheKey );
85-
86- if ($ cacheItem ->isHit ()) {
87- $ this ->logger ?->info(\sprintf ('Cache hit: %s %s ' , $ method , $ uri ), ['key ' => $ cacheKey ]);
88- }
89- else {
90- $ response = ResponseMediator::toArray (
91- $ this ->handleRequest ($ method , $ uri , $ headers , $ body )
92- );
93-
94- $ cacheItem ->set ($ response );
95- $ cacheItem ->expiresAfter ($ this ->cacheTtl );
73+ $ uri = $ this ->buildUrl ($ baseUrl , $ query );
74+ $ response = $ this ->httpClientBuilder ->getHttpClient ()->send ($ method , $ uri , $ headers , $ body );
9675
97- $ this ->cache ->save ($ cacheItem );
76+ if (($ statusCode = $ response ->getStatusCode ()) >= 400 ) {
77+ $ this ->handleResponseErrors ($ response , $ statusCode );
78+ }
9879
99- $ this -> logger ?->info( ' Cached response ' , [ ' ttl ' => $ this -> cacheTtl , ' key ' => $ cacheKey ] );
100- }
80+ return ResponseMediator:: toArray ( $ response );
81+ }
10182
102- return $ cacheItem ->get ();
83+ private function configurePlugins (): void
84+ {
85+ // Plugin order is important
86+ // CachePlugin should come first, otherwise the LoggerPlugin will log requests even if they are cached
87+ if ($ this ->cache !== null ) {
88+ $ this ->httpClientBuilder ->addPlugin (
89+ new CachePlugin ($ this ->cache , $ this ->httpClientBuilder ->getStreamFactory (), [
90+ 'default_ttl ' => $ this ->cacheTtl ,
91+ 'cache_lifetime ' => 0 ,
92+ 'cache_listeners ' => ($ this ->logger !== null )
93+ ? [new LoggerCacheListener ($ this ->logger )]
94+ : []
95+ ])
96+ );
10397 }
10498
105- return ResponseMediator::toArray (
106- $ this ->handleRequest ($ method , $ uri , $ headers , $ body )
107- );
99+ if ($ this ->logger !== null ) {
100+ $ this ->httpClientBuilder ->addPlugin (
101+ new LoggerPlugin ($ this ->logger )
102+ );
103+ }
108104 }
109105
110106 /**
111- * @throws Exception
112107 * @throws NotFoundException
113108 * @throws UnexpectedErrorException
114109 * @throws TooManyRequestsException
115- * @throws BadRequestException
116110 * @throws UnauthorizedException
111+ * @throws BadRequestException
117112 */
118- private function handleRequest (
119- string $ method ,
120- string $ uri ,
121- array $ headers ,
122- StreamInterface |string $ body = null
123- ): ResponseInterface
113+ private function handleResponseErrors (ResponseInterface $ response , int $ statusCode ): void
124114 {
125- $ response = $ this ->httpClient ->send ($ method , $ uri , $ headers , $ body );
126- $ statusCode = $ response ->getStatusCode ();
127-
128- // If API returns an error, throw exception
129- if ($ statusCode >= 400 ) {
130- $ error = new Error (
131- ResponseMediator::toArray ($ response )
132- );
133-
134- match ($ statusCode ) {
135- 400 => throw new BadRequestException ($ error ),
136- 401 => throw new UnauthorizedException ($ error ),
137- 404 => throw new NotFoundException ($ error ),
138- 429 => throw new TooManyRequestsException ($ error ),
139- default => throw new UnexpectedErrorException ($ error )
140- };
141- }
115+ $ error = new Error (
116+ ResponseMediator::toArray ($ response )
117+ );
142118
143- return $ response ;
119+ match ($ statusCode ) {
120+ 400 => throw new BadRequestException ($ error ),
121+ 401 => throw new UnauthorizedException ($ error ),
122+ 404 => throw new NotFoundException ($ error ),
123+ 429 => throw new TooManyRequestsException ($ error ),
124+ default => throw new UnexpectedErrorException ($ error )
125+ };
144126 }
145127
146128 private function buildUrl (UriInterface |string $ baseUrl , array $ query ): string
@@ -156,9 +138,4 @@ private function buildUrl(UriInterface|string $baseUrl, array $query): string
156138
157139 return \sprintf ('%s?%s ' , $ baseUrl , http_build_query ($ query ));
158140 }
159-
160- private function getCacheKey (string $ value ): string
161- {
162- return md5 ($ value );
163- }
164141}
0 commit comments