Happy New Year! :)

Let’s start with a calendar full of Symfony Tips & Tricks from the last SymfonyCon (celebrating Symfony’s 10th birthday):

2016 Calendar

Have a great 2016!

Anúncios

O que mudou na versão 2.2 do Symfony

Na sexta-feira passada (01/03), foi lançada a versão 2.2 do Symfony, que inclui várias funcionalidades e melhorias, que estavam sendo anunciadas semanalmente no blog oficial. Confira aqui um resumo de algumas das novas funcionalidades disponíveis:

Console

Autocompletar na linha de comando: mais uma melhoria para agilizar o desenvolvimento! Agora usando tab e as setas podemos selecionar a resposta rapidamente e sem erros. Você pode passar todas as respostas válidas para o seu comando como último argumento do método askAndValidate():

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

$app = new Application();
$app->register('ask-color')->setCode(function (InputInterface $input,
   OutputInterface $output) use ($app) {
   $colors = array(
              'red', 'blue', 'yellow', 'yellow-light', 'yellow-dark'
             );
   $validation = function ($color) use ($colors) {
       if (!in_array($color, array_values($colors))) {
           throw new \InvalidArgumentException(sprintf(
                         'Color "%s" is invalid.', $color));
       }

       return $color;
   };

   // pergunta e valida a resposta
   $dialog = $app->getHelperSet()->get('dialog');
   $color = $dialog->askAndValidate($output, 
                        'Enter your favorite color (default to red): ', 
                        $validation, false, 'red', $colors);

   $output->writeln(sprintf('You have just entered: %s', $color));
});

$app->run();

O funcionamento do comando, pode ser verificado neste vídeo.

Exibição de uma barra de progresso para as tarefas de longa execução: ao executar comandos de longa duração pela CLI, podemos fornecer um feedback ao usuário, durante a execução do comando, através de um helper de barra de progresso que faz todo o trabalho para você:

$progress = $app->getHelperSet()->get('progress');

$progress->start($output, 50);
$i = 0;
while ($i++ < 50) {     
    // faz algo     
    // avança a barra de progresso em 1 unidade     
    $progress->advance();
}

$progress->finish();

Escondendo as senhas fornecidas na linha de comando: o novo método askHiddenResponse nos permite esconder o que os usuários digitam na linha de comando:

$dialog      = $this->getHelperSet()->get('dialog');
$password = $dialog->askHiddenResponse($output, 'Qual é a senha do banco de dados?');

Restringindo as opções solicitadas ao usuário: há várias formas de pedir algumas informações na CLI. A partir do Symfony 2.2, podemos restringir o que o usuário pode informar através do novo helper select(), fazendo com que ele escolha a partir de uma lista de opções.

Finder

O componente Finder oferece uma agradável DSL para pesquisar arquivos e diretórios. As seguintes melhorias estão disponíveis com a versão 2.2:

Filtro por caminho: com o método path(), que aceita strings ou expressões regulares, agora é possível restringir arquivos e diretórios pelo caminho:
Finder::create()->path('some/special/dir');
Finder::create()->path('/^foo\/bar/');

Para negar a restrição, utilize os métodos notName() e notPath().

Suporte a Glob no método in(): os diretórios onde o Finder deve procurar por arquivos e diretórios podem ser definidos como globs no método in():

Finder::create()->files()->in(
           'src/Symfony/*/*/Resources/translations');

Aumento de velocidade em algumas Plataformas (Linux, MacOs e BSD): o desempenho do Finder foi muito melhorado, através da conversão dos critérios para comandos nativos. Verifique os resultados iniciais do benchmark que foram publicados quando o PR foi submetido.

HttpKernel

Log das chamadas obsoletas: A primeira versão LTS do Symfony2 será a 2.3 (a ser lançada em Maio de 2013) após estão versão, não serão mais realizadas quebras de compatibilidade com as versões anteriores sem uma razão muito boa (ex. uma questão de segurança). Assim, desde a versão 2.0, em vez de apenas substituir ou remover as funcionalidades existentes, elas passam a ser definidas como obsoletas, e serão removidas definitivamente na versão 2.3.

Para fornecer uma transição mais suave, o Symfony 2.2 apresenta um novo recurso: o log das chamadas obsoletas. Sempre que você chamar um método obsoleto ou quando criar uma instância de uma classe obsoleta, o Symfony vai fazer o log da chamada e alertá-lo na barra de ferramentas de depuração. Também é possível verificar exatamente onde a chamada ocorreu no painel de log do profiler web.

Novo sub-framework para gerenciar fragmentos de recursos: um novo sub-framework foi adicionado para lidar com a renderização de fragmentos de recursos e facilitar o uso de diferentes estratégias: sub-requests internos (processados diretamente pelo Symfony), ESIs (processados por um proxy reverso – Varnish, …), HIncludes (processados pelo navegador) e SSIs ( processandos pelo servidor web – Apache, … – somente no Symfony 2.3). O componente HttpKernel pode lidar agora com sub-requests 🙂

Exibição agradável dos erros fatais: os erros fatais são exibidos de uma forma agradável como os outros erros.

Erro fatal no Symfony 2.1:

Mensagem de erro fatal melhorada no Symfony 2.2:

Componente Process

O componente Process permite a execução de sub-processos em PHP, tanto na forma de bloqueio (próximo processo espera a finalização do processo anterior para executar) como sem bloqueio (processos são executados simultaneamente). Ele também ganhou melhorias na nova versão do Symfony:

Obtenção de saída incremental de um Processo: você pode obter os dados de saída incrementais usando os métodos getIncrementalOutput() e getIncrementalErrorOutput(), que retornam as novas saídas desde a última chamada enquanto getOutput() e getErrorOutput() retornam os resultados completos:

use Symfony\Component\Process\Process;

$processes = array();
$processes[] = new Process('ls -lsa');
$processes[] = new Process('ps waux');

while (count($processes) > 0) {
     foreach ($processes as $i => $process) {
         if (!$process->isStarted()) {
             echo "Process starts\n";

             $process->start();

             continue;
         }

         echo $process->getIncrementalOutput();
         echo $process->getIncrementalErrorOutput();

         if (!$process->isRunning()) {
             echo "Process stopped\n";

             unset($processes[$i]);
         }
     }

     sleep(1);
}

Reiniciar um processo: podemos agora reiniciar um processo, por exemplo, no caso dele falhar:

use Symfony\Component\Process\ProcessBuilder;

if (!$process->isRunning()) {
    if (!$process->isSuccessful()) {
        $cloned = $process->restart();

        // ...
    }
}

Obter o status de um processo em execução: ao executar um conjunto de processos, você pode querer reiniciar processos que morreram (como no exemplo anterior). Mas se o processo ainda não é capaz de iniciar, não há motivo para reiniciá-lo. A partir da versão 2.2, você pode verificar o status de um processo e agir em conformidade:

$process->isSuccessful();
$process->hasBeenSignaled();
$process->hasBeenStopped();
$process->isRunning();

// novidade no Symfony 2.2:
$process->isStarted();
$process->isTerminated();

if (!$process->isRunning()) {
    if ($process->isStarted() && !$process->isSuccessful()) {
        $cloned = $process->restart();

        // ...
    }
}

Roteamento

Suporte para host na URL: as rotas contam agora com suporte nativo à host na URL. A constraint do host funciona exatamente da mesma forma como o padrão: ela pode conter placeholders, os placeholders podem ter requisitos, e um requisito do placeholder pode usar algum parâmetro do container de serviço para ser configurado.

Exemplo típico de uso:

user_homepage:
    path: /
    host: "{user}.example.com"
    defaults: { _controller: AcmeDemoBundle:User:profile }

main_homepage:
    path:  /
    defaults: { _controller: AcmeDemoBundle:Main:homepage }

A constraint do host também pode ser adicionada a um conjunto de rotas ao importá-las.

URLs relativas ao esquema e ao caminho: foram adicionados mais dois tipos de URLs que você gerar:

URLs relativas ao esquema: usado quando algumas páginas são acessadas por HTTP ou HTTPS, evitando as warnings dos navegadores.
//example.org/blog/what-a-wonderful-world

{{ url('blog', { post: 'what-a-wonderful-world' }, true) }}

URLs relativas ao caminho: útil quando você precisa gerar arquivos HTML estáticos que podem ser baixados para serem acessados localmente em um navegador (ex: gerador de blog estático)
../ (caminho relativo com base na URL atual)

{{ path('blog', { post: 'what-a-wonderful-world' }, true) }}

Segurança

Utilitários de Segurança: alguns utilitários de segurança foram refatorados para que você possa usá-los em seu próprio código. Estes utilitários estão disponíveis no namespace Symfony\Component\Security\Core\Util.

Geração de um número aleatório seguro: temos a disposição uma implementação robusta para a geração de um número aleatório, com a classe SecureRandom:

use Symfony\Component\Security\Core\Util\SecureRandom;

$generator = new SecureRandom();
$random    = $generator->nextBytes(10);

O método nextBytes() retorna uma string aleatória composta pelo número de caracteres passados ​​como argumento (10 no exemplo acima).

Comparando Strings: Timing attacks ainda não são bem conhecidos, mas mesmo assim, o Symfony possui proteção contra eles. No Symfony 2.0 e 2.1, esta proteção foi aplicada para comparações de senha feitas no bundle Security, mas, a partir do Symfony 2.2, também está disponível para o desenvolvedor:
use Symfony\Component\Security\Core\Util\StringUtils;

// a senha1 é igual a senha2?
$bool = StringUtils::equals($senha1, $senha2);

Validadores

Validadores para pagamento: adicionado novo validador para cartões de crédito, utilizando o algoritmo Luhn:

// src/Acme/SubscriptionBundle/Entity/Transaction.php

use Symfony\Component\Validator\Constraints as Assert;

class Transaction{
    /**
     * @Assert\Luhn(message = "Por favor verifique o número do cartão fornecido.")
     */
    protected $cardNumber;
}

É possível também verificar se um cartão é válido para uma determinada companhia de cartão de crédito com a constraint CardSchemeValidator:

// src/Acme/SubscriptionBundle/Resources/config/validation.yml

Acme\SubscriptionBundle\Entity\Transaction:
    properties:
        cardNumber:
            - CardScheme:
                schemes: [VISA]
                message: O número do cartão de crédito é inválido.

FrameworkBundle

Mais velocidade nos testes funcionais: agora o profiler é desabilitado por padrão nos testes funcionais (na configuração que vem com a Edição Standard):

# in app/config/config_test.yml
framework:
    profiler:
        enabled: false

Cache para páginas estáticas: todos os sites possuem algum tipo de página estática (por exemplo, uma página sobre). Uma página é estática quando não precisa que nenhuma lógica seja processada. Para facilitar neste caso (e evitar ter que criar um controlador e roteamentos para estas páginas), você pode usar o controlador FrameworkBundle:Template:template que configura tudo, diretamente no arquivo de roteamento. Isto funciona desde a versão 2.0, mas na 2.2, você pode definir também a estratégia de cache:

about:
    pattern: /sobre
    defaults:
        _controller: FrameworkBundle:Template:template
        template: 'AcmeBundle:Pages:sobre.html.twig'
        maxAge: 86400
        sharedMaxAge: 86400
        private: false

Novos componentes

Contamos agora com dois novos componentes (que foram extraídos do código existente):

  • Stopwatch – permite medir o tempo de execução de partes específicas do seu código
  • PropertyAccess – função para ler e escrever de/para um array ou objeto utilizando uma notação simples de string

Mais Documentação

Foram adicionados vários artigos na documentação oficial sobre as novas funcionalidades.

Migração da versão 2.1

Se você possui projetos utilizando a versão 2.1, para fazer a migração para a 2.2 deve-se atualizar o arquivo composer.json e executar o composer.phar update.

Após a atualização, verificar com cuidado as modificações citadas neste documento.

Adicionando um novo filtro em seus templates Twig

Adicionar um novo filtro aos seus templates Twig utilizando o Symfony2 é uma tarefa bastante simples, que veremos a seguir, com um exemplo que adiciona um novo filtro unserialize – usando a função PHP com o mesmo nome.

Primeiro, vamos criar uma classe para a nossa nova extensão do Twig, que irá conter o nosso filtro. Para facilitar, podemos estender a classe Twig_Extension, ao invés de implementar a interface Twig_ExtensionInterface, pois esta classe já irá definir todos os métodos para nós, então, não precisamos definir todos novamente, mas somente os que nos interessam ( neste exemplo: getFilters() e getName() ).

A extensão poderá ser salva em qualquer local, neste exemplo iremos salvar em \Extension\Twig dentro do bundle TesteBundle (assumindo que este bundle já foi previamente criado).


\\ Acme\TesteBundle\Extension\Twig\UnserializeTwigExtension.php

<?php  

namespace Acme\TesteBundle\Extension\Twig;

use Symfony\Component\HttpKernel\KernelInterface;

class UnserializeTwigExtension extends \Twig_Extension  
{
  public function getFilters()  
  {
    return array(  
       'unserialize' => new \Twig_Filter_Function('unserialize'),  
    );  
  }  

  public function getName()  
  {  
    return 'unserialize_twig_extension';  
  }  
}

O método getName() deverá retornar um identificador único para a nossa extensão.

No arquivo de configuração config.yml (app/config/config.yml) vamos definir um novo serviço para a classe UnserializeTwigExtension:


services:
  teste.twig.extension.unserializetwigextension:
    class: Acme\TesteBundle\Extension\Twig\UnserializeTwigExtension
    tags:
      -  { name: twig.extension }

Ao aplicarmos a tag para injeção de dependência (DI – Dependency Injection) twig.extension em nosso serviço, estamos informando que nossa classe é uma extensão do Twig personalizada e, também, habilitamos ela.

Pronto! Agora podemos chamar nosso novo filtro unserialize em qualquer template Twig:


# Acme\TesteBundle\Resources\views\Default\index.html.twig
{{ app.session.get('myvar')|unserialize }} 

Para mais informações sobre como estender o Twig criando um novo filtro, tag ou função, verifique a documentação em: http://twig.sensiolabs.org/doc/advanced.html

Até mais 😉

Contribuindo com a tradução da documentação oficial do Symfony2

Interessado(a) em contribuir com a tradução da documentação oficial do Symfony2? Seja bem-vindo(a)!

Este post traz as orientações de como proceder e como estamos nos organizando para a tradução dos documentos. A seguinte thread da lista de discussões sobre o symfony tem as informações iniciais, conforme as instruções da página oficial.

No ano passado, traduzimos o livro “Mais com o symfony 1.3 & 1.4” que foi publicado e está a venda na Amazon.

Então, vamos lá! 🙂

Informando os documentos que deseja traduzir

Para melhor organização, primeiro informar o(s) documento(s) que pretende ajudar na tradução e/ou revisão na planilha de tradutores/revisores.

Se ainda não possuir acesso de edição nesta planilha, solicitar acesso para andreiabohner at gmail dot com.

Utilizando o Git e o github

Agora, para nos auxiliar, temos a nossa disposição o github, uma ferramenta fantástica, onde encontra-se a documentação.
Abaixo está uma descrição sucinta de como utilizar o git e o github.

Para começar, fazer o fork do repositório master da tradução para o português no github:

Agora, você irá “clonar” o projeto para a sua máquina local:
Copiar a URL do repositório do seu fork (semelhante a imagem abaixo), para utilizá-la com o comando git clone:

$ git clone git@github.com:seuusername/symfony-docs-pt-BR.git

Após completar o clone do repositório, ele terá o nome remoto “origin“. Não confundir, apesar do nome ser origin ele não está apontando para o repo master, mas sim para o seu fork no github.

Pronto, agora é só trabalhar na tradução do(s) documento(s).

Finalizadas as traduções e/ou revisões, faça o commit das alterações no seu repositório local:
$ git commit –a –m "pt_BR translation"

E atualize o seu repositório no servidor github com as alterações realizadas localmente:
$ git push origin master

O último passo é informar sobre as suas alterações ao responsável pelo repositório de origem para que ele faça um pull das alterações no repositório. Para isso, acesse a página do repositório original no github, em: https://github.com/andreia/symfony-docs-pt-BR e envie um pull request (clicando no botão “Pull Request”):

Mantendo seu repositório local atualizado

Sempre antes de fazer as suas alterações locais, lembrar de executar o comando pull para manter atualizado o seu repositório local trazendo as alterações do repositório de origem (o repositório que você fez o fork):
$ git remote add upstream git://github.com/andreia/symfony-docs-pt-BR.git
$ git pull upstream master

Formato da documentação

A documentação do Symfony2 utiliza a linguagem markup reStructuredText juntamente com o Sphinx, ao invés do markdown. Segue a referência: http://symfony.com/doc/2.0/contributing/documentation/format.html
Se preferir, existe um editor online, que pode auxiliar em: http://rst.ninjs.org/

Referências sobre o Git / github

Git Cheat Sheet
Working with remotes
Pro Git
My Common Git Workflow

[UPDATE 08/04/2011] Alterado o repositório de http://github.com/andreia/symfony-docs para https://github.com/andreia/symfony-docs-pt-BR

Dica: Definindo um nome personalizado para as tabelas i18n do Doctrine

Pesquisando na documentação do Doctrine e em blogs *around the web* a resposta não encontra-se tão facilmente, então deixo aqui a dica para quem pretende utilizar a internacionalização do banco de dados com o symfony e o behaviour i18n do Doctrine e precisa personalizar o nome das classes para as tabelas i18n 😉

A palavra mágica é tableName. Ela é uma opção do behaviour i18n para definir o nome da classe personalizado, em seu schema do banco:


BlogPost:
  actAs:
    I18n:
      tableName: custom_table_name_translation
      fields: [title]
  columns:
    title: string(255)

A solução está em uma thread no grupo do Doctrine que faz referência ao ticket 1000, onde encontra-se a resposta.

Na documentação do Doctrine sobre o behaviour i18n, onde temos a lista de opções disponíveis para o behaviour, encontramos a opção className (%CLASS%Translation) com a qual podemos definir o nome padrão para utilizar nas classes geradas, porém, esta opção não funcionará se você deseja utilizar um nome para sua tabela que não contenha a palavra Translation no final, como por exemplo, na situação em que você está trabalhando com um sistema legado, e o nome das suas tabelas mais a palavra “Translation”, ultrapassarem o limite do tamanho do banco de dados para tabelas, como no caso do Oracle, por exemplo, que é de 30 caracteres (para todos os seus identificadores).

Symfony 1.4 Cheat-Sheet: Formulários – sfForm (Primeira Parte)

O symfony 1.4 possui um framework MVC de formulários poderoso, que pode, inclusive, ser utilizado independentemente em outros projetos.

Esta primeira parte das referências sobre os formulários do symfony, exibe um esquema exemplo sobre a utilização de um formulário simples e as possíveis configurações relativas aos campos do formulário que podem ser realizadas através do método configure().

Idiomas disponíveis:

  • English: Forms – sfForm (Part I) [PDF]
  • Português: Formulários – sfForm (Parte I) [PDF]