Skip to content

Instantly share code, notes, and snippets.

@doried-a-a
Created May 23, 2020 00:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doried-a-a/d4c577abcf456bf1a72facb352b23260 to your computer and use it in GitHub Desktop.
Save doried-a-a/d4c577abcf456bf1a72facb352b23260 to your computer and use it in GitHub Desktop.
<?php
use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface;
use Predis\Client;
use Symfony\Component\Messenger\MessageBusInterface;
class CacheResolver implements ResolverInterface
{
protected $redis;
protected $redisImageServer;
protected $messengerBus;
public function __construct(Client $imageCacheRedisClient,
MessageBusInterface $bus,
RedisImageServer $redisImageServer
){
$this->redis = $imageCacheRedisClient;
$this->redisImageServer = $redisImageServer;
$this->messengerBus = $bus;
$this->cachePrefix = "image_cache";
}
private function getKey($path, $filter){
$pathKey = $path? md5($path) : "";
return "image_cache_$filter-$pathKey";
}
public function isStored($path, $filter)
{
$key = $this->getKey($path, $filter);
# If we don't have any entries for this image in Redis yet, then no filter was generated
list($isStored, $content) = $this->redis->mget([$key."_stored", $key."_content"]);
if( ($isStored && $isStored !== "false") || $content != null) return true;
return false;
}
public function resolve($path, $filter)
{
$key = $this->getKey($path, $filter);
# If this function was called, there should always be a redis entry (as isStored won't return true unless there is)
$isStored = $this->redis->get($key."_stored");
# if the result was already stored in permanent storage, return the image path from there
# replace following piece of code with something that retuns a deterministic path to your image/filter in your permanent storage (cloud storage)
if($isStored && $isStored !== "false") return $this->mountManager->getWebUrl($this->getFileUrl($path, $filter));
# otherwise, serve it from redis.
# $redisImageServer is just a symfony-service that would return a url to the nodejs service we'll cleate. You can replace this directly
# with something like localhost:8008/get/$key, if you wanted to run the nodejs image service on port 8008
else return $this->redisImageServer->getUrlForImage($key);
}
public function store(BinaryInterface $binary, $path, $filter)
{
$key = $this->getKey($path, $filter);
$values = [
$key."_stored" => false,
$key.'_content' => base64_encode($binary->getContent())
];
$this->redis->mset($values);
$this->redis->expire($key."_content", 60*60);
try {
# this part is to send a message to symfony-messenger that an image filter got applied. You need to configure Messenger correctly
$this->messengerBus->dispatch(new ImageFilterAppliedMessage($key, $this->getFileUrl($path, $filter)));
} catch (\AMQPConnectionException $ee){
error_log("AMQP: could not send ImageFilterAppliedMessage");
}
}
public function remove(array $paths, array $filters)
{
# you'll find a way to implement this ;) it does not matter for this demo
}
protected function getFileUrl($path, $filter)
{
// crude way of sanitizing URL scheme ("protocol") part
$path = str_replace('://', '---', $path);
return $this->cachePrefix.'/'.$filter.'/'.ltrim($path, '/');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment