Skip to content

Commit 728bd4c

Browse files
committed
refactor: cache middleware
1 parent bfef862 commit 728bd4c

1 file changed

Lines changed: 80 additions & 106 deletions

File tree

Lines changed: 80 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,113 @@
11
<?php namespace App\Http\Middleware;
2-
/**
3-
* Copyright 2015 OpenStack Foundation
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
* Unless required by applicable law or agreed to in writing, software
9-
* distributed under the License is distributed on an "AS IS" BASIS,
10-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11-
* See the License for the specific language governing permissions and
12-
* limitations under the License.
13-
**/
142

153
use Closure;
16-
use Illuminate\Support\Facades\Config;
174
use Illuminate\Http\JsonResponse;
18-
use libs\utils\CacheRegions;
19-
use libs\utils\ICacheService;
5+
use Illuminate\Support\Facades\Cache;
6+
use Illuminate\Support\Facades\Config;
207
use Illuminate\Support\Facades\Log;
8+
use libs\utils\CacheRegions;
219
use models\oauth2\IResourceServerContext;
2210

23-
/**
24-
* Class CacheMiddleware
25-
* @package App\Http\Middleware
26-
*/
2711
final class CacheMiddleware
2812
{
29-
/**
30-
* @var ICacheService
31-
*/
32-
private $cache_service;
13+
private IResourceServerContext $context;
3314

34-
/**
35-
* @var IResourceServerContext
36-
*/
37-
private $context;
38-
39-
public function __construct(IResourceServerContext $context, ICacheService $cache_service)
15+
public function __construct(IResourceServerContext $context)
4016
{
4117
$this->context = $context;
42-
$this->cache_service = $cache_service;
4318
}
4419

45-
4620
/**
47-
* @param $request
48-
* @param Closure $next
49-
* @param $cache_lifetime
50-
* @param null $cache_region
51-
* @param null $param_id
21+
* @param \Illuminate\Http\Request $request
22+
* @param Closure $next
23+
* @param int $cache_lifetime seconds
24+
* @param string|null $cache_region one of CacheRegions::*
25+
* @param string|null $param_id route parameter name (e.g. "event_id")
5226
* @return JsonResponse|mixed
5327
*/
5428
public function handle($request, Closure $next, $cache_lifetime, $cache_region = null, $param_id = null)
5529
{
5630
Log::debug('CacheMiddleware::handle');
57-
$cache_lifetime = intval($cache_lifetime);
58-
if ($request->getMethod() !== 'GET') {
59-
// short circuit
60-
Log::debug('CacheMiddleware::handle method is not GET');
61-
return $next($request);
62-
}
6331

64-
$key = $request->getPathInfo();
65-
$query = $request->getQueryString();
66-
$current_time = time();
67-
$evict_cache = false;
68-
if (!empty($query)) {
69-
Log::debug(sprintf('CacheMiddleware::handle query %s', $query));
70-
$query = explode('&', $query);
71-
foreach ($query as $q) {
72-
$q = explode('=', $q);
73-
/*
74-
if(strtolower($q[0]) === "evict_cache"){
75-
if(strtolower($q[1]) === '1') {
76-
Log::debug('CacheMiddleware::handle cache will be evicted');
77-
$evict_cache = true;
78-
}
79-
continue;
80-
}
81-
*/
82-
if(in_array(strtolower($q[0]), ['access_token', 'token_type', 'q', 't','evict_cache'])) continue;
83-
$key .= "." . implode("=", $q);
84-
}
32+
// Only cache GETs:
33+
if ($request->method() !== 'GET') {
34+
Log::debug('CacheMiddleware::handle skipping non-GET');
35+
return $next($request);
8536
}
8637

87-
if (str_contains($request->getPathInfo(), '/me')) {
88-
$current_member = $this->context->getCurrentUser();
89-
if (!is_null($current_member))
90-
$key .= ':' . $current_member->getId();
91-
}
38+
$cache_lifetime = intval($cache_lifetime);
39+
$key = $this->buildKey($request);
40+
$regionTag = null;
9241

93-
$data = $this->cache_service->getSingleValue($key);
94-
$time = $this->cache_service->getSingleValue($key . ".generated");
95-
$region = [];
96-
$cache_region_key = null;
97-
if(!empty($cache_region) && !empty($param_id)){
42+
// If we have a region (e.g. summits/69 → CacheRegionEvents:69):
43+
if ($cache_region && $param_id) {
9844
$id = $request->route($param_id);
99-
$cache_region_key = CacheRegions::getCacheRegionFor($cache_region, $id);
100-
if(!empty($cache_region_key) && $this->cache_service->exists($cache_region_key)) {
101-
//
102-
Log::debug(sprintf("CacheMiddleware::handle trying to get region %s data ...", $cache_region_key));
103-
$region_data = $this->cache_service->getSingleValue($cache_region_key);
104-
if(!empty($region_data)){
105-
$region = json_decode(gzinflate($region_data), true);
106-
Log::debug(sprintf("CacheMiddleware::handle got payload %s for region %s", json_encode($region), $cache_region_key));
107-
}
45+
if ($id) {
46+
$regionTag = CacheRegions::getCacheRegionFor($cache_region, $id);
10847
}
10948
}
110-
if (empty($data) || empty($time) || $evict_cache) {
111-
$time = $current_time;
112-
Log::debug(sprintf("CacheMiddleware::handle cache value not found for key %s , getting from api...", $key));
113-
// normal flow ...
114-
$response = $next($request);
115-
if ($response instanceof JsonResponse && $response->getStatusCode() === 200) {
116-
// and if its json, store it on cache ..).
117-
$data = $response->getData(true);
118-
Log::debug(sprintf("CacheMiddleware::handle storing data for key %s", $key));
119-
$this->cache_service->setSingleValue($key, gzdeflate(json_encode($data), 9), $cache_lifetime);
120-
$this->cache_service->setSingleValue($key . ".generated", $time, $cache_lifetime);
121-
if(!empty($cache_region_key)){
122-
$region[$key] = $key;
123-
Log::debug(sprintf("CacheMiddleware::handle storing data for region %s", $cache_region_key));
124-
$this->cache_service->setSingleValue($cache_region_key, gzdeflate(json_encode($region), 9));
125-
}
126-
}
49+
50+
if ($regionTag) {
51+
Log::debug("CacheMiddleware: using region tag {$regionTag}");
52+
$data = Cache::tags($regionTag)
53+
->remember($key, $cache_lifetime, function() use ($next, $request, $regionTag, $key, $cache_lifetime) {
54+
Log::debug("CacheMiddleware: cache miss for {$key} in tag {$regionTag}");
55+
$resp = $next($request);
56+
if ($resp instanceof JsonResponse && $resp->getStatusCode() === 200) {
57+
return $resp->getData(true);
58+
}
59+
// don’t cache non-200 or non-JSON
60+
return Cache::get($key);
61+
});
12762
} else {
128-
$ttl = $this->cache_service->ttl($key);
129-
// cache hit ...
130-
Log::debug(sprintf("CacheMiddleware::handle cache hit for %s - ttl %s ...", $key, $ttl));
131-
$response = new JsonResponse(json_decode(gzinflate($data), true), 200, [
132-
'content-type' => 'application/json',
133-
]
134-
);
63+
Log::debug("CacheMiddleware: using global cache");
64+
$data = Cache::remember($key, $cache_lifetime, function() use ($next, $request, $key) {
65+
Log::debug("CacheMiddleware: cache miss for {$key}");
66+
$resp = $next($request);
67+
if ($resp instanceof JsonResponse && $resp->getStatusCode() === 200) {
68+
return $resp->getData(true);
69+
}
70+
return Cache::get($key);
71+
});
13572
}
13673

74+
// Build the JsonResponse (either from cache or fresh)
75+
$response = new JsonResponse($data, 200, ['Content-Type' => 'application/json']);
76+
77+
// Mark for revalidation so your ETag middleware can return 304 when unchanged
78+
$response->setPublic();
79+
$response->setMaxAge(0);
80+
$response->headers->addCacheControlDirective('must-revalidate', true);
81+
$response->headers->addCacheControlDirective('proxy-revalidate', true);
82+
13783
return $response;
13884
}
85+
86+
/**
87+
* Build a cache key based on path + sorted query params
88+
*/
89+
private function buildKey($request): string
90+
{
91+
$path = $request->getPathInfo();
92+
$params = collect($request->query())
93+
->except(['access_token','token_type','q','t','evict_cache'])
94+
->sortKeys()
95+
->map(function($v) {
96+
return is_array($v) ? implode(',', $v) : $v;
97+
})
98+
->all();
99+
100+
if (str_contains($path, '/me') && $user = $this->context->getCurrentUser()) {
101+
// per-user cache on /me routes
102+
$path .= ":{$user->getId()}";
103+
}
104+
105+
if (empty($params)) {
106+
return $path;
107+
}
108+
109+
// build a normalized query string
110+
$qs = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
111+
return "{$path}.{$qs}";
112+
}
139113
}

0 commit comments

Comments
 (0)