Sistema de cache mais "inteligente"
Bom, galera... Ainda no desenvolvimento do meu "framework", estou criando um sistema de cache para o backend.
Por enquanto, ele está bem simples: o arquivo de cache trata-se de um arquivo comum de texto (apenas mudo a extensão). A "sacada" é que a primeira linha do arquivo contém o UNIX timestamp que indica a validade do arquivo. Ao ler um arquivo do cache, caso o timestamp seja menor que o timestamp atual ele é ignorado.
Bom, até aí tudo lindo, funciona bem. Eu até criei uma fachada (Facade) para simplifica o uso do cache. A questão é que tudo é manual, desde a definição do diretório do cache até o seu nome. Isso acaba complicando um pouco quando eu preciso compartilhar caches entre diferentes classes.
Como exemplo, imagine que eu tenho uma área administrativa de uma aplicação e uma área pública. Ao buscar o conteúdo pela primeira vez no site público, o cache será realizado pela aplicação, salvando o HTML gerado em um arquivo predefinido. E se eu alterar o conteúdo através da área administrativa, qual o melhor jeito de invalidar o cache? Deixar a aplicação livre pra selecionar pra onde o cache vai e o seu nome me dá a possibilidade de compartilhar nomes de diretórios e arquivos utilizando propriedades e constantes, mas a coisa fica meio bagunçada se o desenvolvedor não seguir um padrão.
Como se trata, em teoria, de um Framework, não basta o "eu sei como utilizar, não vou fazer cagada, deixa como está".
Vou postar só o código da fachada, que acredito ser o mais importante. Caso alguém veja necessidade, posto também o código mais "baixo nível".
<?php
/**
* Controlador simples de cache
* @author <a href="mailto:rick.hjpbacelos@gmail.com">Henrique Barcelos</a>
*/
class Cache_Facade extends Cache_Facade_Abstract {
/**
* @var int
*/
const FILE_APPEND = FILE_APPEND;
/**
* @var NULL
*/
const FILE_OVERWRITE = null;
/**
* @var string
*/
const CACHE_EXTENSION = 'cache';
/**
* Armazena o diretório de cache.
* @var string
*/
private $_cacheDir;
/**
* Construtor.
*
* @param string $cacheDir [OPTIONAL] : o diretório-base para os arquivos de cache
*/
public function __construct($cacheDir = null) {
if($cacheDir !== null) {
$this->setCacheDir($cacheDir);
}
}
/**
* @see Cache_Facade_Abstract::set()
*/
public function set($directory, $fileName, $contents, $expires = null, $flag = null) {
if(!self::isCacheEnabled()) {
throw new Cache_DisabledException('O cache foi desabilitado nesta aplicação!');
}
try {
$dir = new FileSystem_Directory($this->getCacheDir().$directory);
} catch (FileSystem_Directory_Exception $e) {
throw new Cache_WriteException(sprintf('Problemas ao criar do diterório de cache "%s"', $directory));
}
$path = $dir->getPath().$fileName. '.' . self::CACHE_EXTENSION;
if(Cache_File::isFile($path) && !Cache_File::isWritable($path)) {
throw new Cache_WriteException('Permissão negada ao tentar escrever no arquivo de cache ' . $path);
}
if($contents instanceof Serializable) {
$contents = $contents->serialize();
} else {
$contents = serialize($contents);
}
try {
$mode = $flag == self::FILE_OVERWRITE ? Cache_File::LOCK_EX : Cache_File::LOCK_EX | Cache_File::APPEND;
$cacheFile = new Cache_File($path);
$cacheFile->setExpiration($expires);
return $cacheFile->write($contents, $mode);
} catch (FileSystem_File_Exception $e) {
throw new Cache_WriteException('Impossível escrever no arquivo de cache em ' . $path);
}
}
/**
* @see Cache_Facade_Abstract::remove()
*/
public function remove($directory, $fileName) {
if(!self::exists($directory, $fileName)) {
return true;
}
$file = $this->_getFile($directory, $fileName);
return $file->delete();
}
/**
* @see Cache_Facade_Abstract::exists()
*/
public function exists($directory, $fileName) {
if(!FileSystem_Directory::isDir(self::getCacheDir().$directory)) {
return false;
}
$dir = new FileSystem_Directory(self::getCacheDir().$directory);
$path = $dir->getPath().$fileName. '.' . self::CACHE_EXTENSION;
return Cache_File::isFile($path) && Cache_File::isReadable($path);
}
/**
* @see Cache_Facade_Abstract::get()
*/
public function get($directory, $fileName) {
if(!self::isCacheEnabled()) {
throw new Cache_DisabledException('O cache foi desabilitado nesta aplicação!');
}
if(!$this->exists($directory, $fileName)) {
return null;
}
$file = $this->_getFile($directory, $fileName);
if($file->isExpired()) {
return null;
}
$contents = $file->read();
try {
$ret = unserialize($contents);
return $ret === false ? null : $ret;
} catch (ErrorException $e) {
return $contents;
}
}
/**
* Seta o diretório para os arquivos de cache.
*
* @param string $cacheDir : caminho absoluto para o diretório
* ou relatiovo ao diretório padrão de cache da aplicação
* @return Cache_Facade : fluent interface
*/
public function setCacheDir($cacheDir) {
$cacheDir = (string) $cacheDir;
// Caso seja um caminho realativo, deve ser relativo ao diretório padrão
if(strpos($cacheDir, '/') !== 0) {
$cacheDir = Core::getInstance()->getCacheDir() . $cacheDir;
}
$this->_cacheDir = $cacheDir;
return $this;
}
/**
* Retorna o diretório de cache.
*
* @return string
*/
public function getCacheDir() {
// Se não há um diretório de cache setado, usamos o padrão
if($this->_cacheDir === null) {
$this->_cacheDir = Core::getInstance()->getCacheDir();
}
return $this->_cacheDir;
}
/**
* Retorna uma instância de Cache_File com base no diretório e nome informados.
*
* @param string $directory : o subdiretório do arquivo
* @param string $fileName : o nome do arquivo
* @return Cache_File
*/
private function _getFile($directory, $fileName) {
$dir = new FileSystem_Directory($this->getCacheDir().$directory);
$path = $dir->getPath().$fileName. '.' . self::CACHE_EXTENSION;
return new Cache_File($path);
}
}
Valeu!
Discussão (2)
Carregando comentários...