I have many methods in many repositories that have the same logical flow:
- Retrieve value from Cache
- Check value
- If no value, fetch from Database
- Update Cache
- Return value
Is there a way to refactor these methods in such a way that I don’t have to rewrite the same lines over and over again?
I’m using an MVC pattern with services e.g. ActivityService service has ActivityRepositoryInterface (most likely it will be the concrete cached version you see below) injected. I can paste more code if it helps?
Thanks
namespace DWDWBundleRepositoryCached;
use DWDWBundleCacheActivityCache;
use DWDWBundleEntityUser;
use DWDWBundleHelperCacheHelper;
use DWDWBundleRepositoryActivityRepository as ActivityRepositoryInterface;
use DWDWBundleRepositoryDoctrineORMActivityRepository as ActivityRepositoryDoctrine;
class ActivityRepository extends CustomRepository implements ActivityRepositoryInterface
{
private $activityRepository;
private $cacheHelper;
public function __construct(ActivityRepositoryDoctrine $activityRepository, CacheHelper $cacheHelper)
{
parent::__construct($activityRepository);
$this->activityRepository = $activityRepository;
$this->cacheHelper = $cacheHelper;
}
public function findRecentLikeActivity($limit)
{
$key = ActivityCache::KEY_LIKES_WIDGET;
$name = ActivityCache::CACHE_ACTIVITY;
$classType = "ArrayCollection<DWDWBundleEntityActivity>";
$activity = $this->cacheHelper->getFromCache($key, $name, $classType);
if ($activity == null) {
$activity = $this->activityRepository->findRecentLikeActivity($limit);
$this->cacheHelper->saveToCache($key, $name, $activity);
}
return $activity;
}
public function findRecentCommentActivity($limit)
{
$key = ActivityCache::KEY_COMMENTS_WIDGET;
$name = ActivityCache::CACHE_ACTIVITY;
$activity = $this->cacheHelper->getFromCache($key, $name, "ArrayCollection<DWDWBundleEntityActivity>");
if ($activity == null) {
$activity = $this->activityRepository->findRecentCommentActivity($limit);
$this->cacheHelper->saveToCache($key, $name, $activity);
}
return $activity;
}
public function findRecentActivity($limit)
{
$key = ActivityCache::KEY_ALL_WIDGET;
$name = ActivityCache::CACHE_ACTIVITY;
$activity = $this->cacheHelper->getFromCache($key, $name, "ArrayCollection<DWDWBundleEntityActivity>");
if ($activity == null) {
$activity = $this->activityRepository->findRecentActivity($limit);
$this->cacheHelper->saveToCache($key, $name, $activity);
}
return $activity;
}
public function findActivityByUser(User $user)
{
$key = ActivityCache::KEY_USER_ID."_".$user->getId();
$name = ActivityCache::CACHE_ACTIVITY;
$activity = $this->cacheHelper->getFromCache($key, $name, "ArrayCollection<DWDWBundleEntityActivity>");
if ($activity == null) {
$activity = $this->activityRepository->findActivityByUser($user);
$this->cacheHelper->saveToCache($key, $name, $activity);
}
return $activity;
}
public function findActivityOrderedByCreated()
{
$key = ActivityCache::KEY_LIST;
$name = ActivityCache::CACHE_ACTIVITY;
$activity = $this->cacheHelper->getFromCache($key, $name, "ArrayCollection<DWDWBundleEntityActivity>");
if ($activity == null) {
$activity = $this->activityRepository->findActivityOrderedByCreated();
$this->cacheHelper->saveToCache($key, $name, $activity);
}
return $activity;
}
public function findActivityOrderedByCreatedASC()
{
$key = ActivityCache::KEY_LIST_ASC;
$name = ActivityCache::CACHE_ACTIVITY;
$activity = $this->cacheHelper->getFromCache($key, $name, "ArrayCollection<DWDWBundleEntityActivity>");
if ($activity == null) {
$activity = $this->activityRepository->findActivityOrderedByCreatedASC();
$this->cacheHelper->saveToCache($key, $name, $activity);
}
return $activity;
}
}
….
namespace DWDWBundleHelper;
use JMSSerializerSerializer;
use TbbcCacheBundleCacheCacheManagerInterface;
use TbbcCacheBundleCacheKeyGeneratorKeyGeneratorInterface;
class CacheHelper
{
private $cacheManager;
private $keyGenerator;
private $serializer;
public function __construct(CacheManagerInterface $cacheManager,
KeyGeneratorInterface $keyGenerator,
Serializer $serializer)
{
$this->cacheManager = $cacheManager;
$this->keyGenerator = $keyGenerator;
$this->serializer = $serializer;
}
public function getFromCache($key, $name, $classType)
{
$cacheKey = $this->keyGenerator->generateKey($key);
$cache = $this->cacheManager->getCache($name);
$serialized = $cache->get($cacheKey);
$deserialized = $this->deserialize($serialized, $classType);
return $deserialized;
}
public function saveToCache($key, $name, $value)
{
$cacheKey = $this->keyGenerator->generateKey($key);
$cache = $this->cacheManager->getCache($name);
$serialized = $this->serialize($value);
$cache->set($cacheKey, $serialized);
}
public function deleteFromCache($key, $name)
{
$cacheKey = $this->keyGenerator->generateKey($key);
$cache = $this->cacheManager->getCache($name);
$cache->delete($cacheKey);
}
public function serialize($object)
{
return $this->serializer->serialize($object, 'json');
}
public function deserialize($data, $class)
{
return $this->serializer->deserialize($data, $class, 'json');
}
}
You could create a third class that manages both the repository and the cache. Then, don’t manually try to get the cached value and if not available query the repository like
$activity = $this->cacheHelper->getFromCache($key, $name, "ArrayCollection<DWDWBundleEntityActivity>");
if ($activity == null) {
$activity = $this->activityRepository->findRecentCommentActivity($limit);
$this->cacheHelper->saveToCache($key, $name, $activity);
}
Rather have your CachedRepository answer it:
$activity = $this->cachedRepository->getFromCacheOrRepository($key, $name, "ArrayCollection<DWDWBundleEntityActivity>");
The cache and repository query logic can now be implemented in the CachedRepository class and therefore be reused.
3