TWIG L. Gustavo A. TWIG Gustavo Almeida
$whoami
Porque aprender mais uma linguagem ? 1. Ajuda a separar dados e apresentação (MVC). 2. Fim das short open tags do PHP7 (<% …). 3. Contemplado por : Symfony, Drupal8, eZPublish, phpBB, Piwik, OroCRM,Slim, Yii, Laravel, Codeigniter and Kohana. 4. Pre-req : PHP7 para a versao 2 Do fabricante (Symfony) : ● Fast: Twig compiles templates down to plain optimized PHP code. The overhead compared to regular PHP code was reduced to the very minimum. ● Secure: Twig has a sandbox mode to evaluate untrusted template code. This allows Twig to be used as a template language for applications where users may modify the template design. ● Flexible: Twig is powered by a flexible lexer and parser. This allows the developer to define their own custom tags and filters, and to create their own DSL.
Na prática - Imagine trocar isto
Por isso
MYSQL Metodologia MVC TWIG Model (BD) Controller (.php) View (echo) $_GET $_POST http://www.site.com.br/index.php foreach ($produtos as $p){ echo $p[‘nome’]; } model/produtos.php model/categs.php model/usuarios.php detalhes.php carrinho.php listagem.php
<?php ● composer e inicialização (twig, pdo, etc) ● busque no servidor oq eu preciso ● se for o caso analisar $_POST, $_GET ● faça as contas necessárias ● jogue o valor nas variáveis extends ‘principal.twig’ {% for … %} {{ dados }} {% endfor %} use aqui as tags html sem medo de ser feliz echo $twig->render(‘listagem.twig’, [ ‘produtos’=>$produtos, ... ]); MYSQL Metodologia MVC TWIG
Instalando via Composer composer require "twig/twig"
Twig_Autoloader::register();
Ex. prático : Estrutura de diretorios
Banco de dados CREATE TABLE `categorias` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `nome` VARCHAR(40) NOT NULL PRIMARY KEY (`id`) ) CREATE TABLE `produtos` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `nome` VARCHAR(80) NOT NULL, `preco` FLOAT NOT NULL, `estoque` INT(11) NOT NULL, `categ_id` INT(11) NOT NULL PRIMARY KEY (`id`) ) CREATE TABLE `usuarios` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `email` VARCHAR(80) NOT NULL, `senha` FLOAT NOT NULL, `nome` INT(11) NOT NULL PRIMARY KEY (`id`) )
Hello World com TWIG
sintaxe {{ printar coisas }} {% fazer coisas %} {# comentários #}
if e for {% for produto in produtos %} {{ produto.nome }} por R$ {{ produto.preco }} {% if produto.estoque > 0 %} pronta-entrega {% endif %} {% endfor %}
variáveis {% set total=0 %} {{ total }} {% set nome=”Gustavo Almeida” %} {{ nome }} {% set items=[‘fogao’,’geladeira’,’tv’] %} {{ items.1 }}
block, include e extends Com block eu defino no bloco pai, o trecho que vai ser herdado dos filhos. {% block conteúdo %}{% endblock %} Com extends eu defino qual será o bloco pai. {% extends “main.html” %} Exemplo - usar include para incluir o menu de categs. {% include ‘categs.html’ %}
css e js de cada página modularizado {% block css %} <style> </style> {% endblock %} {% block js %} <script> <script> {% endblock %}
block, include e extends PAGINA MODELO includes ‘menu.twig’ block conteudo PAGINA FILHA endblock extends ‘modelo.twig’
block, include e extends global (carrinho, login) categs global include conteudo dinamico {% block content %} {% endblock %} main.twig
global $twig->addGlobal(‘carrinho’,$_SESSION[‘carrinho’]); $twig->addGlobal(‘login’,$_SESSION[‘login’]); Usando as variáveis global : {% if login %} Estou logado {% else %} fazer login {% endif %} Se for um array posso inclusive obter o nome do usuario {{ login.nome }} ou {{ login.imagem }}
macro {% macro input(name,value,type,size) %} <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}"> {% endmacro %} usando as macros : {% import 'forms.twig' as forms %} Login : {{ forms.input('login') }}
filters {{ nome|upper }} {{ idade|default(30) }} {{ 9800.333|number_format(2, '.', ',') }} {{ [1, 2, 3]|join('|') }} Muitas funções do PHP migram para os filtros url_encode, trim, sort, splitround, slice ...
index.php com TWIG require __DIR__.'/../../vendor/autoload.php'; require 'init.php'; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem('views'); $twig = new Twig_Environment($loader); require 'model/produto_model.php'; #globals.php $produtos = getProductsByRand(12); echo $twig->render('index.twig', array('produtos' => $produtos)); $cn->close();
index.twig {% extends main.twig %} {% block content %} {% for produto in produtos %} <p>{{ produto.nome }}></p> <h5>R$ {{ produto.preco }}</h5> {% endfor %} {% endblock %}
categ.twig <ul class="nav list-group"> {% for categoria in categorias %} <li> <a href="listagem.php?id={{categoria.id}}"> {{categoria.nome}} </a> </li> {% endfor %} </ul> {% includes “categ.twig” %}
detalhes.php include 'twig.php'; include 'model/produtos_model.php'; $id = (int) $_GET['id']; $produtos = getProdutoById($id); echo $twig->render('detalhes.twig', array('produto' => $produto));
detalhes.twig {% extends "main.twig" %} {% block content %} {% if produto %} <div class="col-md-12"> <div class="card"> <img src="http://lorempixel.com/450/450/sports/5" class="img-fluid rounded"> <h1>{{ produto.nome }}</h1> <h5>R$ {{ produto.preco }} - {{ produto.disponib }}</h5> </div> </div> {% else %} <h1>Produto Indisponivel ou com erro.</h1> {% endif %} {% endblock %}
cart.php <?php if(!isset($_SESSION[‘cart’])){ $_SESSION[‘cart’]=[]; } if(isset($_REQUEST[‘action’])){ $id=$_GET[‘id’]; switch $_REQUEST[‘action’]{ case ‘add’: $item = getProductById($id); $item[‘qtd’]=1; $_SESSION[‘cart’][$id]=$item; break; case ‘del’: unset($_SESSION[‘cart’][$id]); break; } } echo $twig->render(‘cart.twig’,[ ‘cart’=>$_SESSION[‘cart’] ]); $twig->addGlobal(‘cart’,$_SESSION[‘cart’); # …… {% for item in cart %} {{ item.qtd }} {{ item.nome }} - R$ {{ item.preco }} <a href=#>X</a><br> {% else %} Vazio {% endfor %}
carrinho.twig {% extends "main.twig" %} {% block content %} <table class="table table-striped table-hover table-bordered table-condensed"> <tr> <th>ID</th> ... <th>Total</th> <th>Del</th> </tr> {% set subtotal=0 %} {% set frete=12 %} {% for index,item in carrinho %} <tr> <td>{{ item.id }}</td> <td>{{ item.preco }}</td> <td>X</td> </tr> {# subtotal = subtotal + (item.qtd*item.preco) #} {% else %} <h1>Carrinho vazio</h1> {% endfor %} {% set total = subtotal + frete %} <tr class="warning"> <td colspan="4">SubTotal</td> <td colspan="2">{{ subtotal }}</td> </tr> <tr> {% endblock %} LOOP Cabeçalho tabela Totais
admin.php (CRUD) <?php if(isset($_REQUEST[‘action’])){ switch $_REQUEST[‘action’]{ case ‘add’: $set = parseParamsPost($_POST); $q = sprintf(“INSERT CATEGS SET %s”,$set); $cn->exec($q); break; case ‘del’: $q = sprintf(“DELETE FROM CATEGS WHERE id=%d”,$id); break; case ‘upd’: $q = sprintf(“UPDATE CATEGS SET %s WHERE id=%d,$set,$id)”; break; } } echo $twig->render(‘admin.twig’,[ ‘categs’=>$categs ]); function parseParamsPost(array $post){ $set = “”; foreach($post as $k=>$v){ $set .= “$k= ‘$v’”; } return $set; }
admin.twig {% extends 'main.twig' %} {% block content %} <table class="table table-striped table-hover table-bordered table-condensed"> <tr> <th>id</th> <th>nome</th> <th>upd</th> <th>del</th> </tr> <tr class="table-info"> <form method=post action="?a=add"> <td>X</td> <td><input name="nome"></td> <td colspan=2><button class="btn btn-success">ADD</button></td> </form> </tr> {% for index,categ in categs %} <tr> <form method=post action=”?a=upd”> <td><input type=hidden name='id' value="{{categ.id}}">{{categ.id}}</td> <td><input name='nome' class='form-control' value="{{categ.nome}}"></td> <td><button class='btn btn-info'>UPD</button></td></form> <td>X</td> </tr> {% else %} <tr><td colspan=4>Sem registros</td></tr> {% endfor %} </table> {% endblock %} LOOP REG. NOVO
login.php <?php if($_SERVER[‘REQUEST_METHOD’]===’POST’){ $erros=[]; if(!isset($_POST[‘login’])){ $erros[‘login’]=”login nao informado”; break; } if(!$_POST[‘login’]===’adm’){ $erros[‘login’]=”login nao encontrado”; } if(!$_POST[‘senha’]===’123’){ $erros[‘senha’]=”senha invalida/inconsistente”; } $_SESSION[‘logado’]= empty($erros)? ’sim’ : null; redirect(‘cadastro.php’); } echo $twig->render(‘login.twig’,[ ‘erros’=>$erros ]); $twig->addGlobal(‘logado’,$_SESSION[‘logado’); # …… {% if logado == “sim” %} Ola, {{ logado.user }} <a href=#>Logout</a> {% else %} <a href=#>Login</a> {% endif %}
login.twig {% extends "main.twig" %} {% block content %} {% import 'macros.twig' as forms %} <form method="POST" name="login" action="?a=login"> <legend>Ja sou Cliente</legend> {{ forms.input('login') }} {{ forms.input('senha') }} <button class="btn btn-lg btn-success-outline">Login</button> </form> <form method="POST" name="novo" action="?a=novo"> <legend>Não sou Cliente</legend> <input class="form-control" name="login" placeholder="Email"> <input name="cep" class="form-control" placeholder="CEP"> <button class="btn btn-lg btn-success-outline">Cadastrar</button> </form> {% endblock %}
Certificação em twig
github: lga37 slideshare: lga33 br.linkedin.com/in/lga37

Mini Curso PHP Twig - PHP Conference 2017

  • 1.
  • 2.
  • 3.
    Porque aprender maisuma linguagem ? 1. Ajuda a separar dados e apresentação (MVC). 2. Fim das short open tags do PHP7 (<% …). 3. Contemplado por : Symfony, Drupal8, eZPublish, phpBB, Piwik, OroCRM,Slim, Yii, Laravel, Codeigniter and Kohana. 4. Pre-req : PHP7 para a versao 2 Do fabricante (Symfony) : ● Fast: Twig compiles templates down to plain optimized PHP code. The overhead compared to regular PHP code was reduced to the very minimum. ● Secure: Twig has a sandbox mode to evaluate untrusted template code. This allows Twig to be used as a template language for applications where users may modify the template design. ● Flexible: Twig is powered by a flexible lexer and parser. This allows the developer to define their own custom tags and filters, and to create their own DSL.
  • 4.
    Na prática -Imagine trocar isto
  • 5.
  • 6.
    MYSQL Metodologia MVC TWIG Model(BD) Controller (.php) View (echo) $_GET $_POST http://www.site.com.br/index.php foreach ($produtos as $p){ echo $p[‘nome’]; } model/produtos.php model/categs.php model/usuarios.php detalhes.php carrinho.php listagem.php
  • 7.
    <?php ● composer einicialização (twig, pdo, etc) ● busque no servidor oq eu preciso ● se for o caso analisar $_POST, $_GET ● faça as contas necessárias ● jogue o valor nas variáveis extends ‘principal.twig’ {% for … %} {{ dados }} {% endfor %} use aqui as tags html sem medo de ser feliz echo $twig->render(‘listagem.twig’, [ ‘produtos’=>$produtos, ... ]); MYSQL Metodologia MVC TWIG
  • 8.
  • 9.
  • 10.
    Ex. prático :Estrutura de diretorios
  • 11.
    Banco de dados CREATETABLE `categorias` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `nome` VARCHAR(40) NOT NULL PRIMARY KEY (`id`) ) CREATE TABLE `produtos` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `nome` VARCHAR(80) NOT NULL, `preco` FLOAT NOT NULL, `estoque` INT(11) NOT NULL, `categ_id` INT(11) NOT NULL PRIMARY KEY (`id`) ) CREATE TABLE `usuarios` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `email` VARCHAR(80) NOT NULL, `senha` FLOAT NOT NULL, `nome` INT(11) NOT NULL PRIMARY KEY (`id`) )
  • 12.
  • 13.
    sintaxe {{ printar coisas}} {% fazer coisas %} {# comentários #}
  • 14.
    if e for {%for produto in produtos %} {{ produto.nome }} por R$ {{ produto.preco }} {% if produto.estoque > 0 %} pronta-entrega {% endif %} {% endfor %}
  • 15.
    variáveis {% set total=0%} {{ total }} {% set nome=”Gustavo Almeida” %} {{ nome }} {% set items=[‘fogao’,’geladeira’,’tv’] %} {{ items.1 }}
  • 16.
    block, include eextends Com block eu defino no bloco pai, o trecho que vai ser herdado dos filhos. {% block conteúdo %}{% endblock %} Com extends eu defino qual será o bloco pai. {% extends “main.html” %} Exemplo - usar include para incluir o menu de categs. {% include ‘categs.html’ %}
  • 17.
    css e jsde cada página modularizado {% block css %} <style> </style> {% endblock %} {% block js %} <script> <script> {% endblock %}
  • 18.
    block, include eextends PAGINA MODELO includes ‘menu.twig’ block conteudo PAGINA FILHA endblock extends ‘modelo.twig’
  • 19.
    block, include eextends global (carrinho, login) categs global include conteudo dinamico {% block content %} {% endblock %} main.twig
  • 20.
    global $twig->addGlobal(‘carrinho’,$_SESSION[‘carrinho’]); $twig->addGlobal(‘login’,$_SESSION[‘login’]); Usando as variáveisglobal : {% if login %} Estou logado {% else %} fazer login {% endif %} Se for um array posso inclusive obter o nome do usuario {{ login.nome }} ou {{ login.imagem }}
  • 21.
    macro {% macro input(name,value,type,size)%} <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}"> {% endmacro %} usando as macros : {% import 'forms.twig' as forms %} Login : {{ forms.input('login') }}
  • 22.
    filters {{ nome|upper }} {{idade|default(30) }} {{ 9800.333|number_format(2, '.', ',') }} {{ [1, 2, 3]|join('|') }} Muitas funções do PHP migram para os filtros url_encode, trim, sort, splitround, slice ...
  • 23.
    index.php com TWIG require__DIR__.'/../../vendor/autoload.php'; require 'init.php'; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem('views'); $twig = new Twig_Environment($loader); require 'model/produto_model.php'; #globals.php $produtos = getProductsByRand(12); echo $twig->render('index.twig', array('produtos' => $produtos)); $cn->close();
  • 24.
    index.twig {% extends main.twig%} {% block content %} {% for produto in produtos %} <p>{{ produto.nome }}></p> <h5>R$ {{ produto.preco }}</h5> {% endfor %} {% endblock %}
  • 25.
    categ.twig <ul class="nav list-group"> {%for categoria in categorias %} <li> <a href="listagem.php?id={{categoria.id}}"> {{categoria.nome}} </a> </li> {% endfor %} </ul> {% includes “categ.twig” %}
  • 26.
    detalhes.php include 'twig.php'; include 'model/produtos_model.php'; $id= (int) $_GET['id']; $produtos = getProdutoById($id); echo $twig->render('detalhes.twig', array('produto' => $produto));
  • 27.
    detalhes.twig {% extends "main.twig"%} {% block content %} {% if produto %} <div class="col-md-12"> <div class="card"> <img src="http://lorempixel.com/450/450/sports/5" class="img-fluid rounded"> <h1>{{ produto.nome }}</h1> <h5>R$ {{ produto.preco }} - {{ produto.disponib }}</h5> </div> </div> {% else %} <h1>Produto Indisponivel ou com erro.</h1> {% endif %} {% endblock %}
  • 28.
    cart.php <?php if(!isset($_SESSION[‘cart’])){ $_SESSION[‘cart’]=[]; } if(isset($_REQUEST[‘action’])){ $id=$_GET[‘id’]; switch $_REQUEST[‘action’]{ case ‘add’: $item= getProductById($id); $item[‘qtd’]=1; $_SESSION[‘cart’][$id]=$item; break; case ‘del’: unset($_SESSION[‘cart’][$id]); break; } } echo $twig->render(‘cart.twig’,[ ‘cart’=>$_SESSION[‘cart’] ]); $twig->addGlobal(‘cart’,$_SESSION[‘cart’); # …… {% for item in cart %} {{ item.qtd }} {{ item.nome }} - R$ {{ item.preco }} <a href=#>X</a><br> {% else %} Vazio {% endfor %}
  • 29.
    carrinho.twig {% extends "main.twig"%} {% block content %} <table class="table table-striped table-hover table-bordered table-condensed"> <tr> <th>ID</th> ... <th>Total</th> <th>Del</th> </tr> {% set subtotal=0 %} {% set frete=12 %} {% for index,item in carrinho %} <tr> <td>{{ item.id }}</td> <td>{{ item.preco }}</td> <td>X</td> </tr> {# subtotal = subtotal + (item.qtd*item.preco) #} {% else %} <h1>Carrinho vazio</h1> {% endfor %} {% set total = subtotal + frete %} <tr class="warning"> <td colspan="4">SubTotal</td> <td colspan="2">{{ subtotal }}</td> </tr> <tr> {% endblock %} LOOP Cabeçalho tabela Totais
  • 30.
    admin.php (CRUD) <?php if(isset($_REQUEST[‘action’])){ switch $_REQUEST[‘action’]{ case‘add’: $set = parseParamsPost($_POST); $q = sprintf(“INSERT CATEGS SET %s”,$set); $cn->exec($q); break; case ‘del’: $q = sprintf(“DELETE FROM CATEGS WHERE id=%d”,$id); break; case ‘upd’: $q = sprintf(“UPDATE CATEGS SET %s WHERE id=%d,$set,$id)”; break; } } echo $twig->render(‘admin.twig’,[ ‘categs’=>$categs ]); function parseParamsPost(array $post){ $set = “”; foreach($post as $k=>$v){ $set .= “$k= ‘$v’”; } return $set; }
  • 31.
    admin.twig {% extends 'main.twig'%} {% block content %} <table class="table table-striped table-hover table-bordered table-condensed"> <tr> <th>id</th> <th>nome</th> <th>upd</th> <th>del</th> </tr> <tr class="table-info"> <form method=post action="?a=add"> <td>X</td> <td><input name="nome"></td> <td colspan=2><button class="btn btn-success">ADD</button></td> </form> </tr> {% for index,categ in categs %} <tr> <form method=post action=”?a=upd”> <td><input type=hidden name='id' value="{{categ.id}}">{{categ.id}}</td> <td><input name='nome' class='form-control' value="{{categ.nome}}"></td> <td><button class='btn btn-info'>UPD</button></td></form> <td>X</td> </tr> {% else %} <tr><td colspan=4>Sem registros</td></tr> {% endfor %} </table> {% endblock %} LOOP REG. NOVO
  • 32.
    login.php <?php if($_SERVER[‘REQUEST_METHOD’]===’POST’){ $erros=[]; if(!isset($_POST[‘login’])){ $erros[‘login’]=”login nao informado”; break; } if(!$_POST[‘login’]===’adm’){ $erros[‘login’]=”loginnao encontrado”; } if(!$_POST[‘senha’]===’123’){ $erros[‘senha’]=”senha invalida/inconsistente”; } $_SESSION[‘logado’]= empty($erros)? ’sim’ : null; redirect(‘cadastro.php’); } echo $twig->render(‘login.twig’,[ ‘erros’=>$erros ]); $twig->addGlobal(‘logado’,$_SESSION[‘logado’); # …… {% if logado == “sim” %} Ola, {{ logado.user }} <a href=#>Logout</a> {% else %} <a href=#>Login</a> {% endif %}
  • 33.
    login.twig {% extends "main.twig"%} {% block content %} {% import 'macros.twig' as forms %} <form method="POST" name="login" action="?a=login"> <legend>Ja sou Cliente</legend> {{ forms.input('login') }} {{ forms.input('senha') }} <button class="btn btn-lg btn-success-outline">Login</button> </form> <form method="POST" name="novo" action="?a=novo"> <legend>Não sou Cliente</legend> <input class="form-control" name="login" placeholder="Email"> <input name="cep" class="form-control" placeholder="CEP"> <button class="btn btn-lg btn-success-outline">Cadastrar</button> </form> {% endblock %}
  • 34.
  • 36.