Utilizando Cache em suas Views para Melhorar o Desempenho de seus Módulos PrestaShop

Neste artigo falarei sobre um assunto de grande importância no desenvolvimento de módulos PrestaShop: a utilização de cache para melhorar a performance dos mesmos. A importância desse assunto é maior ainda quando falamos de módulos que são utilizados no Front-Office da loja, pois uma simples um módulo mal escrito pode comprometer seriamente o tempo de carregamento da loja. A boa notícia é que é bastante simples de se utilizar o cache interno do PrestaShop.

Como você já deve saber, todo o HTML da loja é (ou deveria ser) gerado através de alguma linguagem de template (smarty por padrão). Por se tratar de uma linguagem de template, ela deve ser compilada para a obtenção do HTML que será enviado ao navegador. Assim, se nenhum cache for utilizado, toda vez que uma página da loja for acessada, diversos arquivos de template devem ser compilados, mesmo que o resultado da compilação seja exatamente o mesmo que foi produzido na última vez que a loja foi acessada. Além de isso ser um desperdício de recursos do servidor, também faz com que o usuário espere mais tempo do que é necessário para que a página seja carregada. A situação é ainda pior quando o banco de dados precisa ser utilizado para obter os dados a serem utilizados no template.

Mas, conforme já foi dito, o sistema de cache do PrestaShop é bastante simples de ser utilizado, e você só precisará adicionar algumas poucas linhas de código ao seu módulo. Suponhamos que o seu módulo gere algum conteúdo a ser exibido no Front-Office da loja no hook displayShoppingCartFooter. Assim, o seu hook será algo como

Quando esta função for executada, se houver alguma versão do template ‘mytemplate.tpl’ em cache, o PrestaShop automaticamente utilizará essa versão, ao invés de recompilar o template. Se o nosso template não dependesse da variável $data, não precisaríamos fazer nada além disso para utilizar o sistema de cache do PrestaShop. Contudo, conforme o valor do carrinho de compras muda, o HTML produzido por esse template pode ser diferente. Isso faz com que precisemos de versões diferentes em cache desse mesmo template, que possam ser identificadas a partir do valor do carrinho de compras.

Isso pode ser feito utilizando o terceiro argumento do método Module::display(), denominado $cache_id, da seguinte forma:

Assim, o PrestaShop se encarregará de utilizar a versão em cache do template mytemplate.tpl associada ao cache $cache_id. Uma boa prática é utilizar o método Module::getCacheId(), que já gera uma string contendo as seguintes informações:

  • A loja foi acessada utilizando conexão segura ou não;
  • ID da loja acessada (no caso de multilojas);
  • ID do grupo de cliente a que o usuário que acessou a loja pertence;
  • Idioma utilizado pelo cliente no acesso à loja;
  • Moeda utilizada pelo cliente;
  • País selecionado pelo cliente.

Assim, um cache_id bastante interessante pode ser obtido como a seguir

Agora, observe que, caso o template esteja em cache e não precise ser recompilado, o objeto $data$ não será utilizado. Assim, podemos otimizar a nossa função verificando se há algum cache válido para o nosso template antes de chamar o método MyModel::getSomeDbData().

Por fim, a invalidação do cache pode ser feita através do método Module::_clearCache(). Caso desejemos limpar todos os caches associados ao nosso template sempre que sempre que qualquer objeto da classe MyModel for modificado, podemos utilizar o hook actionObjectMyModelUpdateAfter. Esse hook é invocado automaticamente pelo PrestaShop sempre que o método update() for executado com sucesso em um objeto da classe MyModel (que deve extender a classe ObjectModel do PrestaShop).

O método Module::_clearCache() também suporta o parâmetro $cache_id, para que possamos limpar o cache de apenas uma das versões do template.

Desenvolvendo um módulo com CRUD para PrestasShop

Nesse artigo, desenvolveremos um módulo para ser utilizado no painel administrativo da loja. Esse módulo permitirá possuirá as quatro operações CRUD básicas, e mostrará como isso pode ser feito reaproveitando o código do core do PrestaShop. Dessa forma, nossos formulários e a listagem das informações cadastradas possuirão um visual compatível com o padrão da plataforma. Além disso, isso deve fazer com que o módulo seja compatível com futuras versões da loja, até um ponto em que o core seja modificado significativamente.

Os seguintes tópicos serão abordados:

  1. Criação automática do banco de dados;
  2. Reparação (até um certo ponto) automática do banco de dados na reinstalação do módulo;
  3. Listagem dos dados cadastrado no banco em uma grid seguindo o padrão da plataforma;
  4. Criação do formulário de cadastro/edição;
  5. Deleção de registros utilizando ação em massa e individual.

Para os itens 1. e 2., utilizarei a classe CustomObjectModel, que desenvolvi para adicionar alguns recursos à classe ObjectModel do Prestashop.  Para que essa classe funcione bem, os models precisam ser definidos da mesma forma que os models padrão do PrestaShop. Explicarei como fazer essa definição no decorrer do artigo.

Uma vez que os models foram definidos de maneira adequada, os itens 3., 4. e 5. são feitos de maneira praticamente automática pelo próprio PrestaShop. Portanto, nosso trabalho principal será a criação dos models com as definições corretas.

O código-fonte completo do módulo pode ser encontrado neste repositório no GitHub. Para vê-lo em funcionamento, basta extrair todo o código presente no repositório para a pasta /modules/crud/. Recomendo que você siga esse artigo visualizando o código completo do módulo, modificando alguns trechos de seu código para melhor visualização do significado de cada uma das configurações feitas.

Configuração do módulo

Logo no início do arquivo crud.php, temos a linha

A propriedade $models deve conter o nome de todos os models que serão utilizados no módulo. Isso não é um requisito do PrestaShop, mas será utilizado na criação automática do banco de dados. A seguir, temos a definição dasabas que serão criadas no menu do painel administrativo da loja.

Isso fará com que seja criado um menu no painel administrativo da loja com o nome Complete CRUD , com um submenu Custom Operation, conforme a imagem abaixo. Isso também não é feito automaticamente pelo PrestaShop, mas sim com a funçao addTab() que será apresentada a seguir.

Na linha 17, adicionamos o texto a ser exibido no menu (e no submenu) das abas em cada um dos idiomas da loja. Na linha 25, usamos a mesma função addTab() para criar o submenu Custom Operation. A função removeTab(), que será mostrada abaixo, remove os itens que foram criados no menu.

Com essas funções, podemos criar o construtor de nosso módulo, para depois fazer a sua instalação.

Os parâmetros configurados no construtor são auto-explicativos. Sendo assim, seguiremos adiante para a função que instalará o módulo na loja.

Primeiramente, criamos no banco de dados as tabelas referente a cada um dos models utilizados no módulo. Caso as tabelas já existam, a instalação verifica se há alguma coluna faltando nessas tabelas. Isso é util para corrigir eventuais erros provocados por alguma atualização mal-sucedida do módulo. A seguir, instalamos o módulo na loja, e, por fim, criamos o menu do painel referente ao módulo.

Por fim, segue a função uninstall(), que removerá o menu anteriormente criado.

Eu não costumo remover nenhuma informação do banco de dados (muito menos excluir tabelas) na desinstalação do módulo, para evitar perdas acidentais de dados. Ao invés disso, você pode adicionar um botão na tela de configurações do módulo para oferecer essa opção ao usuário, avisando-o das possíveis consequências. Isso não será abordado nesse artigo,

Criação do Model

Na criação do model, muito pouco precisa ser feito. Devemos, apenas, especificar todas as colunas que devem ser criadas no banco de dados, e criar um atributo para cada uma dessas colunas na classe CrudModel. Isso é feito com o código abaixo, que está no arquivo classes/CrudModel.php.

O parâmetro primary refere-se à chave primária da tabela utilizada, e é o campo que será utilizado para identificar unicamente cada registro dessa tabela pelo PrestaShop. As constantes TYPE_INTTYPE_STRING, etc, estão definidas no arquivo ObjectModel.php, dentro da pasta classes da sua loja. validate refere-se ao nome de uma das funções da classe Validate que será utilizada para validar os dados antes de serem salvos no banco de dados. Por fim, o parâmetro db_type não é padrão do PrestaShop, mas acrescentei ele para ser utilizado pela CrudCustomObjectModel, na criação automática do banco de dados.

Criação dos controllers

controller também é bastante simples, assim como foi o model. Devemos apenas configurar quais colunas desejamos que sejam apresentadas na tabela que apresentará os dados. A tabela em si será gerada automaticamente pelo PrestaShop. Do mesmo modo, especificaremos quais os campos presentes nos formulários de cadastro/edição, e o formulário será gerado automaticamente. Não escreveremos uma linha da camada de apresentação (view), nem da parte pesada do controller. O PrestaShop se encarregará de chamar os métodos adequados da classe CrudModel quando o usuário utilizar algum filtro na tabela, ou quando ele editar algum dos registros dela, ou até mesmo quando excluir uma de suas linhas do banco de dados.

As imagens abaixo mostram as telas de listagem e de cadastro que são geradas automaticamente pelo prestashop, no tema padrão do painel administrativo. Para que elas sejam geradas, devemos criar o arquivo controllers/admin/AdminCrudModels.php. Todos os parâmetros necessários para a geração das telas serão configurados no construtor da classe. Assim, comecemos a declaração básica do controller.

Na linha 7, dizemos que esse controller requer que o bootstrap seja carregado para que as views sejam exibidas corretamente. A seguir, especificamos os parâmetros do model cujos dados desejamos manipularPor fim, devemos especificar quais campos desejamos que sejam apresentados na listagem dos dados. Isso é feito através do código abaixo.

As chaves do array acima correspondem aos nomes dos campos que foram configurados no nosso model. Os parâmetros utilizados no código acima seguem a documentação da classe HelperList, então não farei maiores comentários. Na linha 14, fazemos com que a coluna active ganhe a funcionalidade de modificar o status do objeto apenas clicando nos ícones “v” ou “x“. Além disso, a tabela ganha automaticamente as ações em massa “Ativar Aelecionados” e “Desativar Selecionados”.

Para a ação em massa de deleção, devemos adicionar o código abaixo.

Para finalizar nossa listagem, vamos adicionar os botões de ação individual, como mostra a figura abaixo.

Isso é feito facilmente com o código abaixo.

Quando o usuário clicar em Editar, ele verá o formulário abaixo, já preenchido com os dados do objeto escolhido.

Ele pode, ainda, adicionar uma nova linha à tabela com o botão de Adicionar Novo, na parte de cima da tabela. Ele verá o mesmo formulário, mas sem nenhum dado preenchido.

btn_new

Para que esse formulário seja gerado automaticamente, devemos especificar todos os campos que serão exibidos, através do código abaixo.

Essa especificação é feita conforme a documentação da classe HelperForm.

Feito isso, nosso CRUD está finalizado, e totalmente funcional. Note que, como as telas são geradas automaticamente, alguns aspectos da interface não podem ser modificados tão facilmente. Para fazer qualquer modificação não coberta nesse artigo, recomendo uma análise da classe AdminController, bem como as classes HelperFormHelperList, que são as classes base para a geração das telas.

[PrestaShop] – Realizando Requisições AJAX para URLs do Painel

Neste artigo falarei sobre um problema que encontrei quando comecei a desenvolver módulos para a plataforma Prestashop: como realizar requisições AJAX para meus controllers que herdam a classe AdminController.  Apesar de requisições AJAX não serem, em geral, algo complicado de se fazer, essa tarefa se torna um pouco mais complicada quando o destino da requisição é um controller do tipo mencionado.

Primeiramente, para que a requisição seja processada, é necessário que haja um registro na tabela tab referente ao controller para o qual desejamos enviar a requisição. Você pode criar esse registro através da função abaixo:

$tab = new Tab();
$tab->module = <nomedomodulo>;
$tab->active = 0; 
$tab->class_name = <nomedocontroller>;  //AdminCustomProducts por exemplo
$tab->id_parent = Tab::getIdFromClassName(<nomedomodulo>);

foreach (Language::getLanguages(true) as $lang)
{
    $tab->name[$lang['id_lang']] = <nomedaaba>;
}

$tab->add();

Na linha 3, se você deixar a aba como ativa, ela será exibida no menu do Prestashop. Se você estiver criando um controller apenas para se comunicar via AJAX, deixe como 0. Se você deixar active=1, uma aba aparecerá no painel administrativo do usuário com um link para esse novo controller. Na linha 9, o nome da aba é o texto que será apresentado ao usuário no link para o seu controller. Caso você use active=0, esse campo não é importante, e pode conter qualquer valor.

A segunda dificuldade é que toda URL do painel precisa conter um token de segurança válido para que a requisição chegue até o controller desejado. Para que esse token seja acessível via Javascript, eu costumo deixá-lo como atributo de algum div em meu template.

<div id='meumodulo_wrapper' data-token='{$token}'>
	...
</div>

No controller responsável por gerar o template acima, o token de segurança deve ser adicionado à variável “$token“.

$this->smarty->assign(array(
    'token' => Tools::getAdminTokenLite('nomedocontroller')
));

Assim, a requisição ajax pode ser feita da forma a seguir.

$.ajax({
    type : 'POST',
    dataType : 'json',
    url : 'ajax-tab.php',
    data : {
        //parâmetros obrigatórios
        ajax : true,
        controller : 'nomedocontroller',
        action : 'nomedometodo',
        token : $('#meumodulo_wrapper').attr('data-token'),

        //demais dados a serem utilizados pelo controller
        foo : 'bar'
    },
})
.done(function(){})
.fail(function(){});

Isso fará com que a requisição chegue até o método “ajaxProcessnomedometodo()“ do controller “nomedocontroller.php“.  Note que o nome do método é case-sensitive. Por fim, implemente esse método em seu controller.

function ajaxProcessnomedometodo()
{	
    echo json_encode(array(
        'success' => true,
        'received_data' => Tools::getValue('foo')
    ));
}

Utilizando Node.js para o controle de hardware pela WEB através do protocolo Firmata

Neste artigo falarei sobre uma aplicação muito interessante que pode ser feita utilizando-se Node.js: o controle de hardware pela WEB. A aplicação que escolhi foi o controle do estado de diversos leds conectados a um Arduino, com o qual o servidor Node.js se comunicará. É uma aplicação extremamente simples do ponto de vista do hardware, mas que servirá para ilustrar os conceitos necessários para a criação de aplicações mais complexas. O código-fonte completo da aplicação pode ser baixado do repositório no GItHub.

A Aplicação

Primeiramente, descreverei em detalhes a aplicação que será desenvolvida. Ela consistirá de dois leds, que poderão ser acendidos ou apagados pelo usuário através de uma interface WEB. Além disso, o usuário poderá monitorar o estado desses leds a qualquer momento. A mesma aplicação poderá ser utilizada por diversas pessoas, e se um outro usuário alterar o estado de um dos leds através de outra instância da aplicação, os demais usuários serão informados disso em tempo real.

A aplicação é dividida em três partes distintas:

  • Interface do Usuário – Exibe o estado dos dois leds, e permite que esse estado seja modificado. O estado dos leds é mantido atualizado com o estado físico dos mesmos. Essa camada se comunica diretamente com o servidor Node.js;
  • Servidor Node.js – Recebe as solicitações de alteração de estado dos leds, e as repassa ao Arduino. Também é responsável por avisar à camada de interface das mudanças ocorridas no estado dos leds em tempo real. Essa camada se comunica tanto com a interface quanto com a camada de Hardware;
  • Hardware – Consiste dos dois leds mais o Arduino.

A comunicação entre a interface do usuário e o servidor Node.js será feita através da biblioteca http://socket.io, e a comunicação do servidor com o Arduino será feita de maneira serial. Cada uma dessas três partes serão descritas a seguir, de maneira independente.

Interface do Usuário

A interface é bastante simples. Cada um dos leds é representado um ícone, que pode estar em preto (led apagado) ou amarelo (led aceso). Além disso, há dois botões de ação. Se um led estiver aceso, e o botão correspondente a ele for acionado, esse led será apagado; caso contrário, ele será aceso. Os nomes dos leds são referentes aos pinos do Arduino aos quais eles estão conectados fisicamente.

Interface do usuário formada por dois leds, cada um deles com um botão de ação associado.

Para a geração do HTML da página, optei por utilizar a linguagem de template jade. É uma linguagem bastante simples, que facilita a geração do HTML através de uma linguagem mais limpa, e que possui uma série de funcionalidades. Essas funcionalidades não serão detalhadas, mas o leitor que sentir necessidade é convidado a ler a documentação oficial. O código abaixo gera todo o HTML da interface.

O css presente em style.css é bastante simples, então não vou adicioná-lo ao artigo para não deixá-lo desnecessariamente comprido.

Agora, descreverei o código javascript que será responsável por fazer a comunicação entre o navegador e o servidor Node.js. Essa comunicação será feita através da biblioteca socket.io. Ela permite que uma conexão seja mantida aberta entre as duas partes da aplicação, de modo que qualquer uma delas pode enviar uma mensagem para a outra a qualquer momento.

Essa conexão é estabelecida através do código abaixo.

Nesse código, localhost é o endereço do servidor node.js, e 5555 é a porta através da qual as mensagens serão trocadas. Agora, quando um dos botões for pressionado, devemos avisar ao servidor. Isso será feito disparando um evento, que chamarei de toggle_led.

Na linha 3, disparamos o evento toggle_led. Esse evento será “escutado” pelo servidor em tempo real, e terá como parâmetro a variável led_number, que possui o número do led cujo estado deve ser invertido. Por fim, precisamos atualizar o estado dos leds na tela do usuário quando o servidor acender ou apagar algum dos leds.

Nesse caso, o servidor disparará o evento changed, e enviará como parâmetro o estado atual dos dois leds. Assim, cada um dos leds recebe a classe HTML on ou off, dependendo de ele estar aceso ou apagado. Todos os usuários que estiverem utilizando a aplicação escutarão o evento changed quando o servidor modificar o estado de um dos leds. Assim, todos eles terão em sua tela o estado atualizado dos leds.

Servidor Node.js

Apesar de se uma aplicação simples, eu optei por utilizar o framework Express. Desse modo, se eu quiser fazer algo mais complexo futuramente, não haverá grandes dificuldades. Como eu já expliquei o básico sobre esse framework em outro artigo, vou explicar aqui apenas a parte referente à aplicação deste artigo.

Primeiramente, adicione os pacotes socket.iojohnny-five à sua aplicação. O pacote socket.io já foi explicado anteriormente, e o johnny-five é quem fará a comunicação com o Arduino. Abaixo, é feita a  inicialização dos leds e da comunicação com o Arduino .

Na linha 4, devemos informar a porta serial à qual o Arduino se encontra conectado. Na linha 7, o evento ready é disparado pela variável board após a comunicação ter sido estabelecida com a placa. Por fim, após a inicialização dos leds, a função ioChanged() avisará aos usuários da aplicação que o estado dos placa mudou, disparando o evento changed para a camada de interface do usuário. Essa função será apresentada a seguir.

Para permitir a comunicação em tempo real entre o servidor e a camada de interface, devemos inicializar o pacote socket.io, como a seguir.

Assim, quando um usuário se conectar ao servidor através da porta 5555, a função a seguir será executada.

Primeiramente, verificamos se a comunicação entre o servidor e o Arduino já foi estabelecida. Em caso afirmativo, o estado dos leds é enviado para o usuário que acabou de se conectar ao servidor através do evento changed. Na linha 5, sempre que esse usuário gerar o evento toggle_led para o servidor, o estado físico do led correspondente é alterado (linha 6), e, então, todos os usuários que estejam usando a aplicação no momento são avisados disso em tempo real (linha 7).

Por fim, segue a implementação da função ioChanged().

Camada de Hardware

Muito pouco precisa ser feito na camada de hardware para que a comunicação com o servidor seja feita. O pacote johnny-five, responsável por fazer essa comunicação, utiliza o protocolo Firmata. Sendo assim, precisamos gravar um programa no Arduino que seja implemente esse protocolo. Felizmente, a IDE do Arduino já vem com um exemplo que implementa o protocolo Firmata. Assim, só precisamos gravá-lo!

Para isso, vá em File -> Examples  -> Firmata  -> StardardFirmata, como mostra a Figura abaixo.

Feito isso, basta gravar o programa no Arduino, e a comunicação estará funcionando! Agora, basta conectar os leds aos pinos 2 e 13 do Arduino, para que a aplicação esteja finalizada.

 

 

Node.js: Criando um servidor REST com o Padrão MVC utilizando o Framework Express

Olá, já faz um bom tempo que não escrevo por aqui. Estou com pouco tempo livre devido a meu projeto de mestrado. Neste post falarei sobre parte de um projeto recente que venho desenvolvendo, durante o qual precisei criar um servidor REST com Node.js.

Sou um grande fã de CakePHP, pois foi o primeiro framework para web que tive contato, e com o qual aprendi bastante. Talvez por isso, sempre que aprendo uma nova linguagem, procuro encontrar analogias com alguma parte do CakePHP que eu já conheço. Sendo assim, procurei deixar a estrutura da aplicação o mais parecida possível com o que eu utilizava com CakePHP.

obs: se você não está familiarizado com o padrão MVC, leia este artigo.

Neste projeto, a maioria dos métodos dos models utilizam o pacote Bluebird para promessas. Além disso, o banco de dados que escolhi foi o MySQL. Algumas alterações na camada demodels podem ser necessárias se você quiser utilizar outro banco de dados.

O fonte completo da aplicação pode ser baixado aqui.

Estrutura básica da aplicação

Se você já estiver acostumado com o padrão MVC, não terá dificuldades para entender a função de cada diretório da aplicação. Há um diretório para os controllers e um para osmodels, mas nenhum para as views. Optei por retornar os dados do servidor apenas no formato JSON. Caso você deseje suporte para mais formatos, pode utilizar uma camada deviews separada da dos controllers para isso.

Antes de tudo, edite o arquivo config/config.js com as configurações de acesso ao banco de dados e a porta a ser utilizada pela aplicação. Você também pode especificar a porta através da variável de ambiente PORT.

Rotas

O Framework Express já possui um sistema de rotas bastante interessante, então pouco trabalho foi preciso aqui.

Cada controller possui uma função addRestRoutes que adiciona as rotas básicas do servidor automaticamente. Essas rotas mapeiam para ações presentes na classe Controller. Cadacontroller da sua aplicação deve herdar os métodos da classe Controller.

As rotas padrões são no formato a seguir:

  • GET /blog/1: mapeia para a ação findById
  • POST /blogs/searches: mapeia para a ação search
  • POST /blogs: mapeia para a ação create
  • PUT /blog/1: mapeia para a ação edit
  • DELETE /blog/1: mapeia para a ação delete

As ações search, create e edit requerem que alguns parâmetros sejam passados no corpo da requisição.

Para a ação de busca, os parâmetros devem ser passados seguindo o formato a seguir:

Para as ações create e put, devem ser passados os dados a serem salvos no banco de dados.

Se o controller possuir alguma rota que saia deste padrão, elas podem ser adicionadas pelo método addCustomRoutes como a seguir:

Controllers

A estrutura básica para um controller é a seguir.

O arquivo acima deve se chamar CarsController.js e estar na pasta controllers.

Models

Os models precisam de algumas configurações para o correto funcionamento dos métodos da classe Model. Um model básico é apresentado a seguir.

Os principais métodos herdados da classe Model são listados abaixo.

Model.find

Realiza uma consulta ao banco de dados.

Exemplo de Uso

Parâmetros

  • conditions : array de condições no formato do pacote squel
  • limit : máximo de registros para serem retornados
  • offset : números de registros para serem pulados
  • group : cláusula SQL group by
  • recursive : nível de recursividade para buscar por registros nos models com os quais este está associado

Model.findById

Busca por um registro com determinado id. Seu único parâmetro é o id do objeto a ser buscado. Este método retorna uma promessa rejeitada se não houver registro com o id especificado.

Model.save

Cria ou atualiza um registro já existente no banco de dados.

Exemplos de Uso

Model.delete

Remove um registro do banco e dados. Seu único parâmetro é o id do registro a ser removido.

Squel: Gerador de SQL para Node.js

Neste artigo falarei sobre o pacote squel, um gerador de SQL para Node.js. Utilizar um gerador é bastante produtivo, pois evita que tenhamos que escrever e debugar as queries diretamente. Abordarei apenas algumas consultas básicas, mas o pacote é bastante versátil.

Atenção: Embora o pacote também possa ser utilizado pelo browser, você não deve executar em seu servidor consultas geradas pelo cliente, uma vez que isso trás sérios problemas de segurança.

Instalação e Configuração

Para instalá-lo, e adicioná-lo automaticamente às dependências de seu package.json, digite

O pacote não precisa de nenhuma configuração para ser utilizado.

Utilização Básica

Retirei alguns exemplos da documentação oficial.

Insert

Select

Update

Delete

Utilizando Prepared Statements

Sempre que possivel, é recomendável a utilizaçao de prepared statements. Escrevi um artigo que mostra como utilizar prepared statements com o pacote node-mysql2, escrevendo as consultas SQL manualmente.

Para fazê-lo utilizando o pacote squel é bastante simples:

Ainda há muito mais. É possível utilizar subconsultas, condições bastante complexas e a geração de queries com comandos específicos para mysql e postgres. Vale a pena conferir a documentação completa!

Salvando suas views em Cache utilizando Redis e o Framework Express

Olá novamente. Nesse post, mostrarei como utilizar o pacote express-redis-cache para salvar suas views em cache, reduzindo, assim, o tempo de carregamento das páginas.

O pacote é bastante simples de ser utilizado, mas também é bastante completo. Utilizando-o no blog, não senti falta de nenhum recurso adicional. Seu desempenho também é bastante satisfatório, visto que os caches são armazenados num servidor Redis.

Instalação e Configuração

Para instalá-lo, adicione o pacote express-redis-cache às dependências de seu arquivopackage.json, ou digite

Neste tutorial assumirei que a versão do pacote express-redis-cache instalada é a mais recente até o momento (0.1.7).

Para utilizá-lo, devemos informar os parâmetros de conexão do servidor Redis.

O parâmetro prefix é utilizado para formar as string que identificarão cada uma das páginas armazenadas em cache.

Se você já tiver uma conexão Redis estabelecida, pode utilizar o parâmetro {client : redis_client} na inicialização, omitindo host, port e auth_pass. Se for necessário a utilização de senha para a conexão ser realizada, essa é, até o momento, a única forma de isso ser feito.

Utilização Básica

Para utilizar o pacote, devemos adicionar seu middleware a todas as rotas em que desejamos utilizá-lo.

Isso pedirá ao pacote para verificar se há alguma entrada de nome APP_NAME + '/' armazenada em cache. Em caso negativo, a função home será executada, e enviará a string ‘Welcome to my app’ como resposta à requisição.

Essa resposta será automaticamente salva em cache, com a entrada APP_NAME + '/'. Enquanto esse cache não expirar, a função home() não será mais executada.

Alterando o nome das Entradas

Você pode alterar o nome de uma entrada como a seguir.

ou fazendo

ou, ainda,

Decidindo Utilizar (ou não) Cache

Você pode escolher não utilizar a resposta armazenada em cache, mesmo se ela ainda não tiver expirado. Para isso, faça

Sobrescrevendo o parâmetro expire

Para alterar a vida útil padrão do cache, utilize

Excluindo entradas do cache

Você pode excluir entradas do cache, mesmo que elas ainda não tenham expirado.

Se você possui paginação em sua home, com cada página salva com as entradas home.page.0,home.page.1, e assim por diante, você pode excluir todas as entradas numa única chamada à função del().

Debugando

Várias mensagens de log são enviadas pelo pacote utilizado. Para escutá-las, faça

E é isso! Para aplicações de médio/grande porte, salvar as views em cache trará um ganho considerável de performance. Contudo, deve-se tomar cuidado para remover o cache sempre que o conteúdo do site for alterado. Afinal Você não quer uma página com um html antigo incluindo um javascript modificado, quer?

Gerando Sitemap para um Blog feito com o Framework Express para Node.js

Nesse artigo explicarei superficialmente o que são sitemaps, e mostrarei como gerá-los com um pacote já existente. Os exemplos práticos serão focados para a utilização em blogs, mas podem ser facilmente estendidos para qualquer tipo de página web. Os sitemaps gerados permanecerão em cache por 24 horas (tempo esse que pode ser modificado livremente, dependendo do volume de atualização de seu blog).

Optei por utilizar o pacote sitemap, que não é específico para Express, mas que é bastante simples de utilizar e que possui um sistema de caches interessante. Há o pacote express-sitemap, para Express, mas que funciona melhor para sites compostos por páginas estáticas. Para um blog, não encontrei muitas vantagens em utilizá-lo no lugar do pacote sitemap.

Se você já sabe o básico sobre sitemaps, a primeira seção do artigo pode ser ignorada.

Introdução aos sitemaps

Sitemap é um protocolo feito para facilitar a indexação das páginas de um site pelos mecanismos de pesquisa. Ele pode consistir de apenas um arquivo de texto, em que cada linha corresponde à URL de uma página do site que você deseje indexar.

Naturalmente, o fato de uma URL não estar no sitemap não quer dizer que ela não será exibida nas páginas de busca (se é isso o que você deseja, leia sobre robots.txt), e uma URL estar em seu sitemap não quer dizer que ela aparecerá na primeira página de nenhum mecanismo de busca.

Os sitemaps servem apenas como facilitadores, assegurando que nenhuma página de seu site deixe de ser analisada pelos mecanismos de pesquisa, e permitindo que você diga, por exemplo, quais páginas considera mais importantes em seu site.

A forma mais comum de se utilizar sitemaps é através de um arquivo XML, que contém, entre outras informações, a última vez em que cada página foi atualizada e, em média, quão frequentes são essas atualizações.

Acima, a página http://www.example.com/ foi modificada pela última vez em 01/01/2015, espera-se que seja modificada mensalmente, e possui prioridade 0.8 (numa escala de 0 a 1). Uma prioridade maior não garante que sua página aparecerá mais bem posicionada nas buscas, mas diz quais páginas, dentro de seu site, você considera mais importantes.

Instalação e Configuração do Pacote Sitemap

Para instalar o pacote, adicione sitemap às dependências de seu arquivo package.json, ou execute o comando

A seguir, crie o arquivo routessitemap.js, e adicione-o a seu objeto app.

Você pode, então, criar seu objeto sitemap como a seguir.

Acesse seusite/sitemap.xml, e você verá o XML do sitemap, ainda sem a URL de nenhuma página.

Adicionando seus Posts ao Sitemap

Agora, você deve obter as URLs de seu blog, para adicioná-las ao objeto sm. Nem todas as URLs precisam ser adicionadas, mas apenas aquelas que possuam conteúdo relevante. Por exemplo, URLs de paginação ou de filtros, em geral, não possuem conteúdo novo: são apenas formas de facilitar a navegação dentro do site, para que o usuário encontre o que deseja.

Sendo assim, optei por adicionar ao sitemap apenas as URLs referentes aos posts do blog.

O método sm.toXML() verifica há quanto tempo o último XML foi gerado, para determinar se é preciso renovar o XML ou se o último gerado ainda é válido. Isso trás um ganho considerável no tempo de geração do mesmo, se seu sitemap possuir muitas páginas.

Caso você prefira utilizar o pacote express-sitemap, poucas alterações teriam de ser efetuadas. A principal é referente ao cache, que não é gerenciado pelo pacote. Assim, você poderia, por exemplo, utilizar cron jobs para gerar o XML, e salvar em public/sitemap.xml a intervalos regulares, ou salvar numa variável o timestamp da última vez que o sitemap foi gerado.

Utilizando Node.js com banco de dados MySQL

Olá! Neste post, falaremos sobre a utilização de bancos de dados MySQL com Node.js! Utilizarei o driver node-mysql2.

Instalação

Para instalá-lo, execute o comando

A instalação também pode ser feita adicionando o pacote mysql2 à lista de dependências de seu arquivo package.json. Para maiores detalhes consulte package.json.

Configuração

Crie o arquivo `config/database.js’ em seu projeto, e adicione as linhas a seguir, fazendo as alterações necessárias nos parâmetros de configuração.

Veja a lista completa das possíveis configurações aqui.

Utilização Básica

Para estabelecer uma conexão com o banco de dados, adicione as linhas a seguir.

Para realizar operações de banco de dados, é bastante simples:

O método end() fecha a conexão com o banco de dados, aguardando que todas as consultas pendentes sejam realizadas antes disso.

Prepared Statements

Para proteger-se contra SQL Injection, recomenda-se a utilização de prepared_statementssempre que uma consulta utilizar dados vindos do usuário. Além disso, quando várias consultas similares forem utilizadas, as consultas são executadas de maneira muito mais eficiente.

Se preferir, você pode preparar o statement manualmente.

Utilizando Pool de Conexões

Você pode, também, utilizar um pool de conexões. Para tanto, adicione ao arquivoconfig/database.js a seguinte linha:

Esse parâmetro diz o número máximo de conexões que podem ser realizadas em simultâneo com o banco de dados.

A seguir, podemos obter conexões do pool.

Transações

Utilizar transações é bastante simples.

O tratamento de erros foi simplificado por questões de legibilidade.

As funções beginTransaction, commite rollback são apenas formas simplificadas de se executar os comandos START_TRANSACTION, COMMIT e ROLLBACK no banco de dados. Contudo, alguns comandos podem gerar commits implícitos.

Utilizando Promessas

Infelizmente este pacote não suporta, nativamente, a utilização de promessas. Contudo, você pode utilizar as funções promisify() e promisifyAll() do pacote bluebird.

Jade: Criando Blocos Reutilizáveis com Mixins

Os benefícios da modularização já foram amplamente estudados na Engenharia de Software, e não são o foco deste artigo. Nele explicarei apenas o que for relevante do ponto de vista da implementação. Caso esteja interessado, consulte também a documentação oficial (em inglês) sobre como implementar herança de views.

Todos os exemplos utilizados neste artigo foram retirados da documentação oficial (em inglês).

Mixins

Mixins são blocos reutilizáveis de código, permitindo uma melhor organização de nossas views.

Primeiramente, vejamos um exemplo simples, que ilustra a declaração e o uso de mixins.

O código Jade abaixo

gera o HTML

Simples, não? O mixin list pode ser utilizado em qualquer arquivo .jade, desde que o arquivo de sua declaração seja devidamente incluído.

Passagem de parâmetros

Vejamos, agora, um exemplo um pouco mais útil, em que o mixin recebe parâmetros para gerar saídas customizadas.

gera o HTML

Blocos

Além disso, mixins podem receber blocos como parâmetro, para produzirem parte da (ou toda a) saída.

gera o HTML

Atributos Nomeados

Também é possível utilizar atributos nomeados, como mostra o exemplo abaixo.

produzindo o HTML

Por padrão, os atributos são escapados durante a chamada da função. Assim, eles devem ser utilizados no mixin em conjunto com o operador !, para evitar que sejam escapados duas vezes.

Número Deconhecido de Parâmetros

Por fim, ainda é possível utilizar mixins que recebam um número desconhecido de parâmetros.

O código Jade abaixo

produz o HTML