• Twitter
  • GitHub
  • Flickr
  • Skype
  • Contato

Blog

Docker containers para aplicações PHP usando Nginx, PHP7-FPM, MariaDB e phpMyAdmin: Olá! Estou de volta e abraçado à portabilidade. Tudo a ver com o assunto de hoje.  ...

O micro-framework Silex

Silex é um micro-framework intuitivo, conciso e extensível. Construído sobre componentes Symfony2, pode ser usado para criar pequenas e grandes aplicações.
Para instalar o micro-framework, você precisa ter em sua máquina o composer(gerenciador de pacotes) tudo fica mais flexível, não somente para instalar o Silex mas também os Providers, que adicionam funcionalidades ao projeto se necessário. O Silex utiliza o Pimple(DIC) para injeção de dependência, facilitando o uso de bibliotecas de terceiros e deixando bem fácil abstrair o seu código..

Usando o Composer.
Crie um diretório para hospedar seu aplicativo Silex e adicione um arquivo composer.json com a seguinte chamada:

{
    "require": {
        "silex/silex": "~1.3"
    }
}

Caso não tenha o composer, faça o download e execute o comando install, no mesmo diretório do arquivo composer.json
recém criado:

$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar install

Seu diretório agora armazena a pasta vendor,  iremos chamar em nossa aplicação o arquivo /vendor/autoload.php para que tenhamos todos os recursos do Silex.
Podemos iniciar uma aplicação utilizando apenas um arquivo, se desejar. Tudo o que é necessário para ter acesso ao Framework é incluir o carregador automático para criar recursos e suas rotas.

Crie o arquivo .htaccess e depois uma index.php, tudo no mesmo diretório, e inicie sua primeira Aplicação. Veja!

.htaccess

<IfModule mod_rewrite.c>
    Options -MultiViews
 
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    #RewriteBase /
    RewriteRule ^ index.php [QSA,L]
</IfModule>

index.php


<?php
 
require_once __DIR__.'/vendor/autoload.php';
 
$app = new Silex\Application();
 
//Método GET - uma rota para /ola/{nome}
$app->get('/ola/{nome}', function($nome) use ($app) {
    return 'Olá '.$app->escape($nome);
});
 
$app->run();


Quando a rota corresponde, a função é executada e, em seguida, o valor de retorno é enviado de volta para o cliente. Finalmente, o aplicativo é executado.
Vá para o seu navegador: http://localhost/meudir/ola/Fulano. Veja o resultado. É realmente muito fácil!

Quero deixar um exemplo onde construo duas rotas para listar e inserir dados numa tabela de banco de dados.
O Silex é modular e extensível, como mencionei no início do artigo, aos poucos é possível usar provedores de serviço(Providers), quando necessário e de acordo com o crescimento de sua aplicação.
Neste projeto, quero utilizar o Twig Template para formatação do front-end. Veja como instalar e depois registrar este Provider.

Em seu arquivo composer.json, adicione uma nova chamada de instalação para o Twig:

 {
  "require":{
     "Silex/silex":"~1.3",
     "twig/twig": "^1.24"
     }
 }

Rode o Composer:

$ php composer.phar update

Iremos agora registrar nosso novo Provider, o Twig, com $app->register(), passando os seguintes parâmetros:

...
 
$app->register(new Silex\Provider\TwigServiceProvider(), array(
    'twig.path' => __DIR__ ."/frontend",));
 
...

Veja que escolhi adicionar os templates no diretório /frontend.

A instalação é básica, faço uso de pelo menos um único Provider para o artigo não ficar longo demais e não irei utilizar outros, então tenha em mente que o artigo é introdutório.
Seguindo adiante, vou utilizar a PDO para conectar ao banco de dados.
Veja:

...
 
//PDO - mysql
$data_source_name = "mysql:dbname=consumo;host=localhost;charset=utf8";
try {
  // data_source_name, login, senha e tratamento de erros
  $database_handle = new PDO($data_source_name, "login","senha", array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
} catch (Exception $exc) {
  $exc->getMessage();
}
 
...

Lembra da aplicação básica na index.php, com uma rota GET(/ola/{nome}), ela pode ser removida pois iremos utilizar uma nova rota GET(/listar).
Este novo recurso(/listar) será responsável por buscar os dados da tabela estimativa. ( SQL para criar e popular a tabela).

Meu novo recurso(/listar) faz uso da instância PDO($database_handle) e utilizará o Provider(Twig) para renderizar os dados obtidos do banco, exibindo-os em nossa template, que ficarão armazenadas no diretório /frontend:

...
 
$app->get("/listar", function() use($app,$database_handle){
 
    //Utilizando a instância($database_handle)
    $statement_handle = $database_handle->prepare("SELECT id,aparelho,uso_mes,uso_dia,mensal_kwh
                                                    FROM estimativa
                                                    ORDER BY id DESC");
    $statement_handle->execute();
    $response = $statement_handle->fetchAll(PDO::FETCH_ASSOC);
 
  return $app[twig]->render("lista.twig", array('dados' => $response, ));
});
 
$app->run();


Veja que o retorno especifica o Provider(twig), já o método render() recebe parâmetros, o nome do template(lista.twig) para essa rota e um array com os dados.

O recurso que acamos de criar utiliza o método HTTP GET.  Se você já criou a base e populou a tabela, faça um teste: http://localhost/meudir/listar

Agora podemos escrever o segundo recurso que receberá um REQUEST, tratará os dados para inserção e caso contrário a requisição, montará o formulário para entrada de dados.
Será necessário usar o método match(), que corresponde todos os métodos. Vamos criar o segundo recurso(/publicar) que instância PDO($database_handle) e depende de um Request para pegar os dados postados. O Silex utiliza recursos como o HttpKernel(do Symfony2) para requests e responses.

Para que seja possível ter uma instância de requisição em sua aplicação, importe o componente (use Symfony\Component\HttpFoundation\Request;) e passe como parâmetro(Request $request) na função anônima.
Neste simples recurso(/publicar) um condicional verifica se há requisição($request->getContent()) um laço para coletar todos os dados por meio do $request->request->all(), caso contrário colete individualmente como no ex.: $request->request->get('campo_aqui').
Se tudo occorrer como planejado, os dados são inseridos e o método redirect() redireciona para outra rota(/listar), já criada. Se um erro for encontado, nosso tratamento de erro(array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING))) setado na instância da PDO, irá exibir algo.
Não havendo requisição, tudo isso é deixado de lado, não entra no condicional e o recurso então renderiza o template('publicar.twig') que contém o formulário.
Veja:

...
 
//importando
use Symfony\Component\HttpFoundation\Request;
 
$app = new Silex\Application();
 
...
 
$app->match('/publicar', function(Request $request) use($app, $database_handle){
    //
    if($request->getContent()){
 
       foreach ($request->request->all() as $key => $value) {
          if($key == "submit") continue;
          $post[$key] .= $value;
        }
 
      $statement_handle = $database_handle->prepare("INSERT INTO estimativa (aparelho,uso_mes,uso_dia,mensal_kwh)
                                                        VALUES (:aparelho,:uso_mes,:uso_dia,:mensal_kwh)");
       $statement_handle->execute($post);
 
      return $app->redirect('listar');
    }
 
   return $app[twig]->render('publicar.twig');
 
});


Vamos partir para nossos templates(lista e publicar) com Twig que auxilia no tratamento de dados para a montagem do HTML.
Num exemplo simples dentro do modelo lista.twig, podemos ver o uso moderno de tratamento, num laço o array 'dados', que foi lançado pelo recurso(/listar) da aplicação é percorrido e armazenado cada linha na variável 'info':

{% for info in dados %}
    {{info.aparelho}}
  {%  endfor %}
 

Já o modelo publicar.twig, é só montar um formulário que passe todos os campos(aparelho,uso_mes,uso_dia,mensal_kwh) os mesmos nomeados dentro do INSERT, após VALUES (:aparelho,:uso_mes,:uso_dia,:mensal_kwh):
Para montar meu formulário, utilizei um recurso legal tipo uma função. Assim como escrever uma função em PHP para fazer e retornar algo, você pode usar uma macro para gerar alguma saída.
Macros são usados para a geração de marcação que podem variar.
Você pode criar um esqueleto  com parâmetros macro.

Crie um arquivo forms.html e adicione:

{% macro input(name, value, type, size, class) %}
    <input type="{{ type|default('text') }}"
          name="{{ name }}" id="{{ name }}"
          value="{{ value|e }}"
          size="{{ size|default(20) }}"
          class="{{ class }}" required="required" />
{% endmacro %}


Agora importe o forms.html e adicione uma chama dentro do arquivo publicar.twig

{% import "forms.html" as forms %}
{{ forms.input('aparelho',null,null,100,'form-control') }}

Veja o formulário completo:

<form action="publicar" method="POST">
  <label for="aparelho">Aparelho:</label>
    {{ forms.input('aparelho',null,null,100,'form-control') }}
  <label for="uso_mes">Dias Estimados(Uso/Mês):</label>
    {{ forms.input('uso_mes',null,null,80,'form-control') }}
  <label for="uso_dia">Média(Utilização/Dia):</label>
    {{ forms.input('uso_dia',null,null,50,'form-control') }}
  <label  for="mensal_kwh">Consumo Médio Mensal(KWh):</label>
    {{ forms.input('mensal_kwh',null,null,50,'form-control') }}
    {{ forms.input('submit','Publicar','submit',null,'btn btn-default') }}
</form>


Dica:
 Alguns navegadores não suportam diretamente o uso de outros métodos HTTP, fora os métodos mais utilizados(GET e POST).
 Para usar PUT por exemplo, você terá que criar um campo de formulário especial com um nome _method, porém a chamada method do formulário deve ser definido como POST:

  <form action="/my/target/route/" method="post">
      <!-- ... -->
      <input type="hidden" id="_method" name="_method" value="PUT" />
  </form>

Pronto, nosso simples projeto está configurado, rodando dois recursos e com um único Serviço(Twig). Porém, não deixarei a aplicação assim, mais serviços serão adicionados para enxugar o código e melhorar recursos, no segundo artigo explico como substituir o modo como a conexão ao banco de dados é feita. 

Vou comitar, e subir o projeto para o GitHub.
Não esqueça de olhar a documentação: silex.sensiolabs.org
[],s