Elabore Web sites rapidamente com o CakePHP, Parte 5: Adicionando cache

Um bom jeito de melhorar o desempenho de seus aplicativos

O CakePHP é uma ferramenta de auxílio estável, pronta para a produção e rápida para o desenvolvimento de Web sites em PHP. Esta série "Elabore Web sites rapidamente com o CakePHP" mostra como construir um catálogo de produtos on-line usando o CakePHP. A Parte 5 lida com execução de cache, especificamente efetuando cache de visualização e layout, que pode ajudar a reduzir o consumo dos recursos do servidor e acelerar seu aplicativo.

Duane O'Brien, PHP developer, 自由职业者

Duane O'Brien é um canivete suíço tecnológico desde que o Oregon Trail era somente texto. Sua cor favorita é sushi. Ele nunca foi à Lua.


nível de autor Contribuidor do
        developerWorks

02/Jun/2009 (Primeira publicação 16/Jan/2007)

Nota do editor: Esta série foi originalmente publicada em 2006 e atualizada em 2007 e 2008. Desde sua última publicação, os desenvolvedores do CakePHP fizeram alterações no CakePHP, que resultaram nas diversas revisões desta série. Esta revisão foi escrita para o CakePHP V1.2.2.8120.

Esta série "Elabore Web sites rapidamente com o CakePHP" foi elaborada para desenvolvedores de aplicativos PHP que desejam começar a usar o CakePHP para facilitar suas vidas. No final, será possível aprender como instalar e configurar o CakePHP, o básico do design Model-View-Controller (MVC), como validar dados de usuários e usar os helpers no CakePHP, e como colocar um aplicativo em execução rapidamente usando o CakePHP. Pode parecer que há muito para aprender, mas não se preocupe — o CakePHP faz a maior parte do trabalho por você.

Este artigo considera que você já tenha concluído a Parte 1, Parte 2, Parte 3 e Parte 4, e que você ainda tenha o ambiente de trabalho configurado para estas partes. Se não tiver instalado o CakePHP, será necessário ler as Partes 1 e 2 antes de continuar.

Consideramos que você conheça o PHP, tenha um entendimento básico de design de bases de dados e que fique à vontade durante o trabalho.

Requisitos do sistema:

Antes de começar, você precisa ter um ambiente em que possa trabalhar. O CakePHP tem requisitos de servidor razoavelmente mínimos:

  1. Um servidor HTTP que suporte as sessões (e, de preferência, mod_rewrite). Este tutorial foi escrito usando o Apache V2.2.4 com o mod_rewrite habilitado.
  2. PHP V4.3.2 ou mais recente (incluindo PHP V5). Este tutorial foi escrito usando o PHP V2.3.
  3. Um mecanismo de banco de dados suportado. Este tutorial foi escrito usando o MySQL V5.0.4.

Também será necessário um banco de dados pronto para que seu aplicativo possa usá-lo. O tutorial fornecerá a sintaxe para criar todas as tabelas necessárias no MySQL.

O modo mais simples de fazer o download do CakePHP é visitar CakeForge.org e executar o download da última versão estável. Este tutorial foi escrito usando a versão 1.2.812.0. (Também estão disponíveis construções e cópias noturnas direto do Subversion. Os detalhes encontram-se no Manual do CakePHP (consulte Recursos).

Tor, até agora

Na Parte 4, você teve a oportunidade de simplificar o Tor. Como você se saiu?

Adicionando as ações e visualizações favoritas

Para exibir a lista de favoritos, é necessário adicionar uma ação de favoritos ao controlador de usuários. Isso pode parecer um pouco com a Lista 1.

Lista 1. Adicionando uma ação de favoritos ao controlador de usuários
 function favorites () { $username =
                $this->Session->read('user'); $favorites = array(); if ($username) {
                $this->User->recursive = 2; $results =
                $this->User->findByUsername($username); foreach($results['Product'] as
                $product) { $favorites[] = array('Product' => $product, 'Dealer' =>
                $product['Dealer']); } $this->set('products', $favorites); } else {
                $this->redirect(array('controller' => 'users', 'action' =>
                'login')); } }

Observe o redirecionamento se o usuário não tiver efetuado login. Isso impede que o usuário veja um erro ao visualizar a página sem efetuar login.

Também seria necessário o favorites.ctp no diretório app/views/users. Ele pode ser um pouco parecido com o que é mostrado abaixo.

Lista 2. Favorites.ctp.
 <div
                class='favorites'> <h2>Favorites</h2>
                <table cellpadding="0" cellspacing="0"> <tr>
                <th>Id</th> <th>Title</th>
                <th>Dealer</th>
                <th>Description</th> <th
                class="actions">Actions</th> </tr> <?php
                $i = 0; foreach ($products as $product): $class = null; 
                if 
                ($i++ % 2 == 0) { $class
                = ' class="altrow"'; } ?> <tr<?php echo
                $class;?>> <td> <?php echo
                $product['Product']['id'] ?> </td> <td>
                <?php echo $product['Product']['title'] ?> </td>
                <td> <?php echo $html->link($product['Dealer']
                ['title'], array('controller'=> 'dealers', 'action'=>'view', $product
                ['Dealer']['id'])); ?> </td> <td> <?php
                echo $product['Product']['description'] ?> </td> <td
                class="actions"> <?php echo $html->link('View', array
                ('controller' => 'products', 'action'=>'view', $product['Product']
                ['id'])); ?> </td> </tr> <?php endforeach;
                ?> </table> </div>

Tudo o que a visualização realmente precisa fazer é mostrar a tabela de produtos. Porém, agora não há como remover um produto de sua lista de favoritos.


Inserindo o link Excluir de Favoritos

Sua outra tarefa foi inserir um link Excluir de Favoritos na tabela de produtos, configurando-o de modo que os usuários visualizassem o link Excluir, se um produto estivesse em sua lista de favoritos, e um link Adicionar, se o produto não estivesse nela. Olhando novamente para a visualização de produtos, a seção abaixo é a mais importante.

Lista 3. Tabela de produtos
                <?php
                if 
                ( isset($ajax) ) 
                { echo $ajax->link('Add to Favorites', array('action'
                => 'addToFavorites/' . $product['Product']['id']), array('update' =>
                'favMessage')); } 
                else 
                { echo $html->link('Add to Favorites', array('action'
                => 'addToFavorites/' . $product['Product']['id'])); } ?>

O link Excluir de Favoritos será muito parecido com o mostrado abaixo.

Lista 4. Link Excluir de Favoritos
                echo $ajax->link('Remove From Favorites', array('action' =>
                'removeFromFavorites/' . $product['Product']['id']), array('update' =>
                'favMessage'));

Será necessário adicionar também os helpers do JavaScript e do Ajax ao controlador de usuários, e adicionar a ação removeFromFavorites ao controlador de produtos.

Lista 5. A ação removeFromFavorites
 function removeFromFavorites($id) { $username =
                $this->Session->read('user'); $success = false; $user =
                $this->Product->User->findByUsername ($username, 'User.id');
                $this->Product->User->id = $user['User']['id']; $success =
                $this->Product->User->removeFavorite($id); if (
                $this->RequestHandler->isAjax() ) { echo 'Removed product from
                favorites'; exit; } else { if ( $success ) {
                $this->Session->setFlash('Removed product from favorites');
                $this->redirect('/users/favorites'); } else {
                $this->Session->setFlash('Access denied');
                $this->redirect('/products/index'); } } }

Do mesmo modo, você precisa adicionar o método removeFavorite ao modelo de usuários.

Lista 6. Criando o método removeFavorite
 function removeFavorite($product_id) {
                if($this->exists()) { $user = $this->read(); $fav = array();
                foreach($user['Product'] as $product)
                { if ($product_id != $product['id']) { $fav[]
                = $product['id']; } } $user['Product'] = array('Product'=> $fav);
                if($this->save($user)) { return true; } else { return false; } } return
                false; }

Como você pode ter notado ao testar isso, quando você visualiza um produto, Adicionar a Favoritos é sempre exibido. Em vez disso, o usuário deve visualizar o link Excluir de Favoritos para produtos já adicionados à lista de favoritos. Como você faria isso?

Há grandes chances de que sua solução seja muito diferente. Não há problema algum. Agora vamos para o último tópico desta série: Armazenamento em Cache.


Armazenamento em Cache

Conceitualmente, o armazenamento em cache pode ser confuso algumas vezes. Há muitos tipos de armazenamento em cache e cada um apresenta seu próprio conjunto de desafios e benefícios. É importante entender o significado do armazenamento em cache neste contexto.

O que significa armazenamento em cache?

Geralmente, o armazenamento em cache ocorre sempre que é feito um pedido, e o aplicativo que responde diz: "eu não preciso buscar isso. Já tenho um." Na maioria das vezes, quando um usuário de computador ouve a palavra "cache", ele pensa em um cache de navegador. Tipicamente, para acelerar a experiência do usuário, seu navegador manterá cópias do que ele acredita serem arquivos estáticos — geralmente imagens, folhas de estilo, HTML estático e arquivos de script. Embora este tipo de execução de cache às vezes possa causar problemas para os desenvolvedores de aplicativos da Web, ele não constitui nosso foco aqui.

Outro exemplo de armazenamento em cache seria quando o navegador faz um pedido de algum conteúdo a seu aplicativo da Web. Se seu aplicativo da Web usa armazenamento em cache, ele pode responder o pedido com uma cópia anteriormente gerada do conteúdo,eliminando o recurso de código extra envolvido na geração do conteúdo uma segunda vez. Este é o tipo de armazenamento em cache que constitui o foco deste artigo.

Por que cache?

Geralmente, você usaria armazenamento em cache em seu aplicativo por dois motivos. Primeiro, porque ele ajuda a reduzir o consumo de recursos em seu servidor. Embora as economias possam ser pequenas na maioria dos casos, nos sites de alto tráfego que atendem pedidos em volume significativo, estas pequenas economias somam-se rapidamente em benefícios significativos de desempenho. O segundo motivo típico é a velocidade. Em razão de seu aplicativo não ter que passar pelo processo de gerar novamente o conteúdo para o pedido, o conteúdo pode ser servido com muito mais rapidez. Novamente, embora as economias possam ser pequenas na maioria dos casos, os sites de alto tráfego podem obter rapidamente benefícios de velocidade usando a execução de cache.

Como fazer cache?

OK — você comprou a ideia. Você está pronto para fazer cache de toda e qualquer coisa. Como você faz isso? O que o CakePHP lhe proporciona para facilitar isso?

Para começar, você precisa ligar o cache. Por padrão, ele está desabilitado. Você pode habilitá-lo em app/config/core.php. Procure a entrada a seguir: //Configure::write('Cache.check', true); e exclua as barras de comentário da linha.

Estabelecendo Cache.check como verdadeiro, você estará dizendo ao CakePHP que o armazenamento em cache está ativado agora. Vá em frente e faça isso agora para poder iniciar o armazenamento em cache mais tarde. Ainda não acabou: Você precisar dizer exatamente ao CakePHP o que deseja que fique em cache e por quanto tempo.


Do que se deve fazer cache

Tendo ativado o armazenamento em cache, você precisa especificar o que deseja que fique em cache. Isso começa no controlador para as visualizações que você deseja que fiquem em cache, adicionando cache ao array dos helpers. Por exemplo, para fazer cache nas visualizações dos produtos, você teria que incluir Cache no array de helpers do controlador de produtos. Quando construiu o controlador de produtos do Tor, você especificou que os helpers do HTML e formulários estavam em uso. Adicionando Cache a esta lista, o array dos helpers ficaria assim: var $helpers = array('Html', 'Form', 'Javascript', 'Ajax', 'Cache' );.

Agora que o helper do cache está em uso, você precisa especificar exatamente o que deseja colocar em cache. Há muitas maneiras de fazer isso, mas todas elas se apóiam no array $cacheAction.

Fazer cache de um pedido específico

Suponha que você quisesse fazer cache de um pedido específico. Por exemplo, haveria três ou quatro produtos que têm alto tráfego na ação visualizar, e você deseja fazer cache somente das visualizações Visualizar destes produtos. Nesse caso, você especificaria os pedidos do que deseja fazer cache, como chaves de array para $cacheAction, e especificaria o tempo como valor da chave. O array $cacheAction é uma variável de classe, como o array $helpers. Para fazer cache destas visualizações específicas, o $cacheAction poderia se parecer com a Lista 7

Lista 7. $cacheAction
 <?php class ProductsController extends
                AppController 
              { ... var $cacheAction = array ( 'view/1/' => 3600, 'view/2/'
                => 3600, 'view/3/' => 3600 );

Este $cacheAction está dizendo ao CakePHP para fazer cache das visualizações de Visualizar para os produtos 1-3 por 3.600 segundos (uma hora). O tempo que você especifica pode estar em qualquer formato que o strtotime() possa interpretar. Você poderia dizer simplesmente 1 hora.

Fazer cache de uma ação inteira

Talvez não seja suficiente apenas fazer cache de alguns produtos. Talvez você queira fazer cache de todas as visualizações de uma ação específica. Suponha que você queira usar o armazenamento em cache nas visualizações da ação editar. Para isso, você especificaria a ação como uma chave de array e o tempo para manter as visualizações em cache, bem semelhante ao que fez acima.

 var $cacheAction = array ( 'edit/' => '+1 hour' );

Você pode até misturar e combinar as duas.

Lista 8. Misturar e combinar
 var
                $cacheAction = array ( 'view/1/' => 3600, 'view/2/' => 3600, 'view/3/'
                => 3600, 'edit/' => '+1 hour' );

Isso ajuda a economizar um pouco de tempo. Agora você fez cache das visualizações de Visualizar dos produtos mais comumente visualizados e de todas as visualizações de editar. Mas talvez você deseje fazer mais.

Faça cache de tudo o que o controlador faz

Talvez você deseje fazer cache de tudo que o controlador faz. Se quiser, não é necessário especificar cada ação no array $cacheAction. Você pode simplesmente definir o valor de $cacheAction para um tempo que mantenha tudo em cache: var $cacheAction = "+1 hour";.

O valor precisa ser uma cadeia de caractere que o strtotime() consiga interpretar. Definindo $cacheAction como um valor exclusivo, o CakePHP sabe como executar cache de todas as visualizações do controlador.

Fazer cache de dentro de uma ação

Em razão de $cacheAction ser uma variável de classe, você também pode acessar a variável de dentro de uma ação. Supondo que quisesse modificar $cacheAction de dentro de uma ação, você usaria a mesma sintaxe que usaria para modificar qualquer variável de classe.

 function foo() { $this->cacheAction = array()... }

Isso geralmente não seria necessário, mas você encontraria uma ocasião na qual isso é exatamente o que você precisa. Se for esse o caso, agora você sabe que pode. O CakePHP proporciona a você diversas maneiras de fazer cache de suas visualizações. Esta é a parte fácil. Aprender quando fazer cache — ou, mais especificamente, quando não fazer cache—, pode ser um pouco complicado.


Quando fazer cache?

O armazenamento em cache pode arrebatar você como a melhor coisa inventada desde o pão fatiado. Além disso, na maioria das vezes, a execução de cache é exatamente o que você deseja que ela seja. Então, quando você não deve fazer cache de suas visualizações?

Na maior parte do tempo, você não desejaria fazer um cache completo de dados que são atualizados constantemente. Por exemplo, suponha que os usuários do Tor estivessem adicionando produtos diversas vezes por minuto. Nesse caso, o armazenamento em cache da visualização do índice seria comprovadamente mais um problema do que uma ajuda. Se o conteúdo está sendo atualizado com tanta frequência que a página em cache nunca é realmente servida, tudo o que você fez foi adicionar o código extra para salvar a página em cache e checá-la para ver se foi atualizada para cada pedido.

Porém, isso não quer dizer que o armazenamento em cache seja inútil. Você só precisa ser mais específico quando disser ao CakePHP do que deseja fazer cache.

Visualizar a marcação <cake:nocache><cake:nocache>

Dentro de uma visualização ou layout, o CakePHP permite que você exclua especificamente alguns conteúdos da execução de cache agrupando o conteúdo nas tags <cake:nocache><cake:nocache>. O uso apropriado desta marcação permitirá que o CakePHP faça cache das partes estáticas da visualização ou layout enquanto assegura que as partes dinâmicas da página sejam recuperadas em cada pedido.

Nem tudo pode ser agrupado nas tags <cake:nocache><cake:nocache>. Especificamente, você não pode agrupar variáveis nas tags <cake:nocache><cake:nocache para torná-las dinâmicas. Em termos gerais, as coisas que podem ser agrupadas nas tags cake:nocache><cake:nocache> são construtos do CakePHP, como helpers e chamadas de elementos.

Por exemplo, no Tor, o layout padrão criado na Parte 4 continha uma saudação por nome de usuário.

Lista 9, Layout padrão
 <!DOCTYPE
                html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html
                xmlns="http://www.w3.org/1999/xhtml"> <head> ... <div
                id="header"> <h1><?php echo $html->link('Tor',
                '/') ?> : Welcome <?php echo $session->read('user')
                ?></h1> ...

Se o armazenamento em cache estiver desabilitado, na primeira vez que qualquer página que utilizar o padrão for carregada, a saudação Bem-Vindo <?php echo$session->('user') ?> seria substituída por algo como Bem-Vindo ou Bem-Vindo zaphod -- o que significa que, independente do usuário tivesse efetuado login, ele sempre veria um nome de usuário em cache.

Para especificar que o nome do usuário não deve ficar em cache, você agruparia a linha <?php echo $session->read('user') ?> nas tags <cake:nocache></cake:nocache>. O resultado final ficaria assim:

Lista 10. Especificando que o nome do usuário não deve ficar em cache
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML
                1.0 Transitional//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html
                xmlns="http://www.w3.org/1999/xhtml"> <head> ... <div
                id="header"> <h1><?php echo $html->link('Tor',
                '/') ?> : Welcome <cake:nocache><?php echo
                $session->read('user')
                ?></cake:nocache></h1> ...

Você pode testar isso especificando que o controlador de produtos use a execução de cache para a ação visualizar. Adicione o cache à lista de helpers e especifique uma visualização em $cacheAction.

Lista 11. Especificando que o controlador de produtos use o armazenamento em cache para a ação visualizar.
 <?php class ProductsController extends
                AppController 
                { var $name = 'Products'; var $helpers = 
                array('Html', 'Form',
                'Javascript', 'Ajax', 'Cache' ); 
              var $components =
                array
          ('Acl','Security','RequestHandler'); 
          var $cacheAction = array( 'view/'
                => '+1 hour' ); ...

Agora, visualize um produto. Você deverá visualizar um arquivo criado em app/tmp/cache/views que corresponda ao produto que você visualizou. Faça login como um usuário diferente e visualize o mesmo produto. Você descobrirá que seu nome do usuário não está em cache. Edite o produto. Você descobrirá que o CakePHP sabe que você excluiu a exibição em cache. Não é eficiente?

Usar as tags <cake:nocache></cake:nocache>pode ajudá-lo a encontrar o equilíbrio delicado entre fazer cache de suas visualizações e manter seu conteúdo atualizado. Às vezes isso não é o bastante. Algumas vezes você mesmo precisa limpar o cache.


Quando limpar o cache

Mesmo se você for esperto quanto ao que fica em cache e o que não fica, às vezes é necessário limpar o cache manualmente. Você pode estar pensando que isso será obviamente necessário quando os dados foram atualizados. Por exemplo, se um produto for editado, o visualizar ou editar visualizações daquele produto, bem como o índice de produtos, teriam que ser todos limpos do cache. E você tem razão. Eles precisam ser limpos.

Mas você não precisa fazer isso. O CakePHP faz isso por você. O CakePHP sabe quando os dados são inseridos, atualizados ou excluídos, e se isso afetar uma visualização em cache, o cache desta visualização será limpo. Isso economiza uma quantidade monstruosa de trabalho.

Mas pode ser necessário limpar o cache explicitamente. Por exemplo, se um processo externo, como um script de batch planejado, estiver atualizando os dados diretamente no banco de dados em vez de usar o aplicativo diretamente, o cache precisaria ser limpo manualmente. Isso pode ser feito com o uso da função global clearCache.

Como limpar o cache

Você normalmente nunca precisaria limpar o cache, pois o CakePHP limpa os arquivos relacionados ao cache quando há um INSERT, UPDATE ou DELETE para os dados destes arquivos.

Se você quiser limpar todo o cache, pode chamar a função Cache::clear()em uma ação de limpeza de cache específica, ou então pode criar um controlador explicitamente para este propósito. Isso seria especialmente prático se você precisasse automatizar o processo.


Resumo

Parabéns! Você concluiu a série 'Elabore Websites rapidamente com o CakePHP" Você provavelmente está preparado para criar seu novo aplicativo.

Mas, antes de fazer isso, configure DEBUG como 2 em appconfigcore.php. Isso dirá ao CakePHP para exibir algumas informações de depuração do SQL na parte inferior de suas visualizações. Você pode encontrar as páginas em cache em app/tmp/cache/views. Abra uma delas e dê uma olhada em como será a aparência de uma página em cache. Exclua os arquivos em cache e visualize um produto. Faça uma anotação de quantas queries foram executadas e quanto tempo elas levaram. Agora, recarregue A visualização está em cache. Quantas queries foram executadas desta vez? Quanto tempo isso levou? Familiarize-se com a execução de cache. Procure maneiras de usá-lo no Tor. Quando acabar, jogue tudo fora e mergulhe em seu próprio aplicativo.

Você aprendeu muito com esta série, mas nada colocará este aprendizado em perspectiva como escrever seu próprio aplicativo do zero no CakePHP.


Download

DescriçãoNomeTamanho
Part 5 source codeos-php-cake5.source.zip14KB

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=406276
ArticleTitle=Elabore Web sites rapidamente com o CakePHP, Parte 5: Adicionando cache
publish-date=06022009