mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-08 18:44:30 +00:00
246 lines
6.2 KiB
PHP
246 lines
6.2 KiB
PHP
<?php
|
|
/*
|
|
* This file is part of Phraseanet
|
|
*
|
|
* (c) 2005-2016 Alchemy
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Alchemy\Phrasea\Databox\Subdef;
|
|
|
|
use Alchemy\Phrasea\Cache\MultiAdapter;
|
|
use Doctrine\Common\Cache\Cache;
|
|
use Doctrine\Common\Cache\MultiGetCache;
|
|
use Doctrine\Common\Cache\MultiPutCache;
|
|
|
|
class CachedMediaSubdefDataRepository implements MediaSubdefDataRepository
|
|
{
|
|
/**
|
|
* @var MediaSubdefDataRepository
|
|
*/
|
|
private $decorated;
|
|
|
|
/**
|
|
* @var Cache|MultiGetCache|MultiPutCache
|
|
*/
|
|
private $cache;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $baseKey;
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
private $lifeTime = 0;
|
|
|
|
/**
|
|
* @param MediaSubdefDataRepository $decorated
|
|
* @param Cache $cache
|
|
* @param string $baseKey
|
|
*/
|
|
public function __construct(MediaSubdefDataRepository $decorated, Cache $cache, $baseKey)
|
|
{
|
|
$this->decorated = $decorated;
|
|
$this->cache = $cache instanceof MultiGetCache && $cache instanceof MultiPutCache
|
|
? $cache
|
|
: new MultiAdapter($cache);
|
|
$this->baseKey = $baseKey;
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function getLifeTime()
|
|
{
|
|
return $this->lifeTime;
|
|
}
|
|
|
|
/**
|
|
* @param int $lifeTime
|
|
*/
|
|
public function setLifeTime($lifeTime)
|
|
{
|
|
$this->lifeTime = (int)$lifeTime;
|
|
}
|
|
|
|
/**
|
|
* @param int[] $recordIds
|
|
* @param string[]|null $names
|
|
* @return array
|
|
*/
|
|
public function findByRecordIdsAndNames(array $recordIds, array $names = null)
|
|
{
|
|
$keys = $this->computeKeys($recordIds, $names);
|
|
|
|
if ($keys) {
|
|
$data = $this->cache->fetchMultiple($keys);
|
|
|
|
if (count($keys) === count($data)) {
|
|
return $this->filterNonNull($data);
|
|
}
|
|
}
|
|
|
|
return $this->fetchAndSave($recordIds, $names, $keys);
|
|
}
|
|
|
|
/**
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
private function filterNonNull(array $data)
|
|
{
|
|
return array_values(array_filter($data, function ($value) {
|
|
return null !== $value;
|
|
}));
|
|
}
|
|
|
|
public function delete(array $subdefIds)
|
|
{
|
|
$deleted = $this->decorated->delete($subdefIds);
|
|
|
|
$keys = array_map([$this, 'dataToKey'], $subdefIds);
|
|
|
|
$this->cache->saveMultiple(array_fill_keys($keys, null), $this->lifeTime);
|
|
|
|
return $deleted;
|
|
}
|
|
|
|
public function save(array $data)
|
|
{
|
|
$this->decorated->save($data);
|
|
|
|
// all saved keys are now stalled. decorated repository could modify values on store (update time for example)
|
|
$recordIds = [];
|
|
|
|
foreach ($data as $item) {
|
|
$recordIds[] = $item['record_id'];
|
|
}
|
|
|
|
$keys = array_merge(array_map([$this, 'dataToKey'], $data), $this->generateAllCacheKeys($recordIds));
|
|
|
|
array_walk($keys, [$this->cache, 'delete']);
|
|
}
|
|
|
|
/**
|
|
* @param array $data
|
|
* @return string
|
|
*/
|
|
private function dataToKey(array $data)
|
|
{
|
|
return $this->getCacheKey($data['record_id'], $data['name']);
|
|
}
|
|
|
|
/**
|
|
* @param int $recordId
|
|
* @param string|null $name
|
|
* @return string
|
|
*/
|
|
private function getCacheKey($recordId, $name = null)
|
|
{
|
|
return $this->baseKey . 'media_subdef' . json_encode([(int)$recordId, $name]);
|
|
}
|
|
|
|
/**
|
|
* @param int[] $recordIds
|
|
* @param string[] $names
|
|
* @return string[]
|
|
*/
|
|
private function generateCacheKeys(array $recordIds, array $names)
|
|
{
|
|
$names = array_unique($names);
|
|
$namesCount = count($names);
|
|
|
|
$keys = array_map(function ($recordId) use ($namesCount, $names) {
|
|
return array_map([$this, 'getCacheKey'], array_fill(0, $namesCount, $recordId), $names);
|
|
}, array_unique($recordIds));
|
|
|
|
return $keys ? call_user_func_array('array_merge', $keys) : [];
|
|
}
|
|
|
|
/**
|
|
* @param int[] $recordIds
|
|
* @return string[]
|
|
*/
|
|
private function generateAllCacheKeys(array $recordIds)
|
|
{
|
|
$recordIds = array_unique($recordIds);
|
|
|
|
return array_map([$this, 'getCacheKey'], $recordIds, array_fill(0, count($recordIds), null));
|
|
}
|
|
|
|
/**
|
|
* @param int[] $recordIds
|
|
* @param string[]|null $names
|
|
* @param string[] $keys Known keys supposed to be fetched
|
|
* @return array
|
|
*/
|
|
private function fetchAndSave(array $recordIds, array $names = null, array $keys = [])
|
|
{
|
|
$retrieved = $this->decorated->findByRecordIdsAndNames($recordIds, $names);
|
|
|
|
$data = $this->normalizeRetrievedData($retrieved, $keys);
|
|
|
|
$toCache = null === $names ? $this->appendCacheExtraData($data, $retrieved, $recordIds) : $data;
|
|
|
|
$this->cache->saveMultiple($toCache, $this->lifeTime);
|
|
|
|
return $this->filterNonNull($data);
|
|
}
|
|
|
|
/**
|
|
* @param int[] $recordIds
|
|
* @param string[]|null $names
|
|
* @return string[]
|
|
*/
|
|
private function computeKeys(array $recordIds, array $names = null)
|
|
{
|
|
if (!$recordIds) {
|
|
return [];
|
|
} elseif (null !== $names) {
|
|
return $this->generateCacheKeys($recordIds, $names);
|
|
}
|
|
|
|
$keys = $this->generateAllCacheKeys($recordIds);
|
|
$data = $this->cache->fetchMultiple($keys);
|
|
|
|
return count($keys) === count($data) ? call_user_func_array('array_merge', $data) : [];
|
|
}
|
|
|
|
/**
|
|
* @param array $retrieved
|
|
* @param array $keys
|
|
* @return array
|
|
*/
|
|
private function normalizeRetrievedData(array $retrieved, array $keys)
|
|
{
|
|
$data = array_fill_keys($keys, null);
|
|
|
|
foreach ($retrieved as $item) {
|
|
$data[$this->dataToKey($item)] = $item;
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* @param array $data
|
|
* @param array $retrieved
|
|
* @param array $recordIds
|
|
* @return array
|
|
*/
|
|
private function appendCacheExtraData(array $data, array $retrieved, array $recordIds)
|
|
{
|
|
$extra = array_fill_keys($this->generateAllCacheKeys($recordIds), []);
|
|
|
|
foreach ($retrieved as $item) {
|
|
$extra[$this->getCacheKey($item['record_id'])][] = $this->getCacheKey($item['record_id'], $item['name']);
|
|
}
|
|
|
|
return array_merge($data, $extra);
|
|
}
|
|
}
|