Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Henrique Barcelos

Sistema de cache mais "inteligente"

Recommended Posts

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!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Invalidar que você se refere na área administrativa é "expirar" ou ao "editar" o cache você regravaria ele e tornaria disponível aos usuários a versão atualizada?

 

O que eu entendo que você precisa é de uma automatização? Ou estou enganado?

 

Por exemplo se o administrador editar a página de busca:

http://site.com/busca/

 

invalidaria todas as páginas em cache geradas a partir dela? Por exemplo:

http://site.com/busca/?q=termo 1
http://site.com/busca/?q=termo 2
http://site.com/busca/?q=termo 3
http://site.com/busca/?q=termo 3&orde=asc

 

É isso?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Exato... Eu não queria ter que fazer isso manualmente, pois planejo utilizar muito cache, acabaria ficando complicado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.