Após uma longa pausa, voltamos com a sequencia de artigos sobre o Laravel. No artigo de hoje vamos falar sobre como funciona o sistema de templates do Laravel, o Blade. Após uma introdução mais teórica, vamos modificar as views do aplicativo que estamos construindo para utilizar não apenas o Blade, mas também o Bootstrap.
Blade
Blade é o sistema de templates que faz parte do Laravel. Se você já trabalhou com Smarty, vai perceber que o Blade é muito parecido. Para quem nunca utilizou um sistema de templates deste tipo, ele basicamente é uma maneira diferente de escrever suas views. Em vez de utilizar tags PHP diretamente no seu HTML, você vai utilizar outra sintaxe com chaves e arrobas.
Para indicar que uma view está no formato blade, devemos nomear o arquivo como <nome>.blade.php. Isto é o suficiente para que o Laravel saiba que você utilizará estruturas do Blade nesta view. Outra coisa importante é que você pode continuar utilizando os mesmos códigos PHP, mesmo quando estiver utilizando o Blade. Na realidade o Laravel vai converter todos os códigos Blade em código PHP, então é apenas uma maneira de simplificar o código. Vamos direto ao que interessa, vendo os diferentes códigos que podemos construir utilizando Blade.
Sintaxe
O Blade define uma sintaxe diferente do que estamos acostumados com o PHP. A grande vantagem disso é a clareza da sintaxe, deixando nossos arquivos de views mais limpos. Para equipes que trabalham com designers isso facilita bastante. Vamos ver quais são os comandos disponíveis no Blade.
Echo
Quando precisamos imprimir algo no HTML da view utilizamos o comando echo do PHP.
1 2 3 4 5 6 7 |
<h2><?php echo $artigo->titulo; ?></h2> <small> <a href="artigos/editar/<?php echo $artigo->id; ?>" title="Editar">Editar</a> | <a href="artigos/remover/<?php echo $artigo->id; ?>" title="Remover">Remover</a> </small> <p><?php echo $artigo->conteudo; ?></p> |
No Blade basta utilizar chaves duplas {{ }} ao redor do que precisamos imprimir, da seguinte forma:
1 2 3 4 5 6 7 |
<h2>{{{ $artigo->titulo }}}</h2> <small> <a href="artigos/editar/{{ $artigo->id }}" title="Editar">Editar</a> | <a href="artigos/remover/{{ $artigo->id }}" title="Remover">Remover</a> </small> <p>{{ $artigo->conteudo }}</p> |
Nesse código você pode perceber o uso de chaves duplas {{ }} e triplas {{{ }}}. A diferença é que as chaves duplas vão apenas imprimir o conteúdo da variável, enquanto as chaves triplas vão converter caracteres especiais para HTML e depois imprimir o conteúdo.
Neste print você pode ver a diferença. No título utilizei a tag H1. Como utilizamos chaves triplas, a tag foi exibida com caracteres HTML <h1>. Já no corpo do artigo utilizei a tag STRONG. Como dessa vez foram utilizadas chaves duplas, o conteúdo foi impresso com <strong>, e o browser colocou o texto em negrito.
Mas o que acontece se você quiser exibir chaves duplas no seu HTML? Basta adicionar um arroba antes do código:
1 |
@{{ Seu texto entre chaves }} |
Outra coisa que fica facilitada pelo Blade é quando você precisa testar se uma variável foi definida antes de imprimir a mesma, utilizando isset().
1 2 3 4 5 |
<!-- Este código testa se a variável existe ou imprime um valor padrão --> {{{ isset($nome) ? $nome : 'Valor padrão' }}} <!-- Este código faz a mesma coisa --> {{{ $nome or 'Valor padrão' }}} |
Blocos Se Então
O Blade também implementa sua versão dos blocos IF ELSE.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<h1>Artigos</h1> <a href="artigos/inserir" title="Novo">Novo artigo</a> | @if ($artigos->count() === 1) Você possui um artigo. @elseif ($artigos->count() > 1) Você possui {{ $artigos->count() }} artigos. @else Você não possui nenhum artigo. @endif <hr> @if($artigos->count()) <?php foreach ($artigos as $artigo) : ?> <h2>{{{ $artigo->titulo }}}</h2> <small> <a href="artigos/editar/{{ $artigo->id }}" title="Editar">Editar</a> | <a href="artigos/remover/{{ $artigo->id }}" title="Remover">Remover</a> </small> <p>{{ $artigo->conteudo }}</p> <hr> <?php endforeach; ?> @else <h2>Nenhum artigo encontrado.</h2> @endif |
O Blade permite utilizar a lógica inversa do IF, executando um bloco somente se a condição for falsa:
1 2 3 |
@unless ($artigos->count()) Você não possui nenhum artigo. @endunless |
Repetições
Também podemos fazer repetições como FOR, FOREACH e WHILE.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!-- Imprimindo nossos artigos --> @foreach ($artigos as $artigo) <h2>{{{ $artigo->titulo }}}</h2> <small> <a href="artigos/editar/{{ $artigo->id }}" title="Editar">Editar</a> | <a href="artigos/remover/{{ $artigo->id }}" title="Remover">Remover</a> </small> <p>{{ $artigo->conteudo }}</p> <hr> @endforeach <!-- FOR apenas para exemplo --> @for ($i = 0; $i < 10; $i++) O valor de i é {{ $i }}. @endfor <!-- WHILE apenas para exemplo --> @while (true) Looping infinito. NÃO FAÇA ISSO! @endwhile |
Comentários
Mais uma coisa que podemos fazer no Blade é criar comentários. Os comentários são convertidos para comentários em PHP <?php // Comentário ?>, desta maneira eles não vão aparecer no HTML final.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{{-- Verifica se existem artigos --}} @if($artigos->count()) {{-- Imprimindo nossos artigos --}} @foreach ($artigos as $artigo) <h2>{{{ $artigo->titulo }}}</h2> <small> <a href="artigos/editar/{{ $artigo->id }}" title="Editar">Editar</a> | <a href="artigos/remover/{{ $artigo->id }}" title="Remover">Remover</a> </small> <p>{{ $artigo->conteudo }}</p> <hr> @endforeach @else <h2>Nenhum artigo encontrado.</h2> @endif |
Múltiplos Templates
Um problema comum quando trabalhamos com várias views é a repetição de conteúdo. Se você olhar o código da nossa aplicação no Github, vai ver que nas views sempre repetimos o cabeçalho HTML. Isso pode facilmente ser evitado no Blade. Ele permite tanto incluir uma view dentro da outra quanto trabalhar com layouts.
Layouts
Os layouts servem para criar a estrutura base para suas views. Você pode colocar toda a estrutura do HTML em um arquivo de layout e implementar apenas o conteúdo principal (apenas o que vai dentro do BODY) nas suas views. Um arquivo de layout pode ter o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!-- Arquivo app/views/layouts/padrao.blade.php --> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Lista de Artigos</title> </head> <body> <div class="container"> @yield('content') </div> </body> </html> |
Quando você possui um layout, basta estender o mesmo nas suas views, desta forma:
1 2 3 4 5 6 |
@extends('layouts.padrao') @section('content') <h1>Artigos</h1> <!-- restante do conteúdo --> @stop |
Perceba que o Laravel aceita que você utilize uma view usando o formato diretorio.arquivo além do formato mais tradicional diretorio/arquivo.
Incluindo Views
Você também pode chamar uma view dentro de outra. Se você criar uma barra lateral (sidebar) por exemplo, pode incluir ela diretamente em outro aquivo Blade.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Lista de Artigos</title> </head> <body> @include('barra-lateral', array('informacao' => $informacao)) <div class="container"> @yield('content') </div> </body> </html> |
Aplicação
O próximo passo é implementar o Blade na nossa aplicação. Além de fazer isso também quero adicionar o Bootstrap para darmos uma aparência mais legal para o nosso aplicativo. Vamos começar criando o arquivo de layout e adicionando o Bootstrap. Depois vamos alterar nossas views.
Layout
Crie um novo arquivo em views/layouts/ chamado padrao.blade.php. Neste arquivo vamos colocar o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ $titulo or 'Desenvolvendo com Laravel' }}</title> <link rel="stylesheet" href="{{ asset('assets/css/bootstrap.min.css') }}"> </head> <body> @include('templates.menu') <div class="container"> @yield('content') </div> <script src="{{ asset('assets/js/jquery-1.11.1.min.js') }}"></script> <script src="{{ asset('assets/js/bootstrap.min.js') }}"></script> </body> </html> |
Neste arquivo temos as tags de cabeçalho do HTML. No título da página estamos usando uma variável título, se ela não for definida, será exibido o título Desenvolvendo com Laravel. Também está sendo incluído uma outra view pra nosso menu (depois vou mostrar ela).
Além disso, foram adicionados códigos para o CSS do Bootstrap e JS do jQuery e do Bootstrap. Portando visite http://getbootstrap.com/ e baixe o Bootstrap. Copie os diretórios para public/assets. Depois faça o download o jQuery em http://code.jquery.com/jquery-1.11.1.min.js e salve o arquivo no diretório public/assets/js.
Menu
Agora que temos o Bootstrap, podemos fazer um design legal no nosso aplicativo. Vamos começar criando um menu. Por enquanto ele será estático, mas no futuro vou mostrar como deixar ele mais dinâmico. Crie o arquivo views/templates/menu.blade.php. Nosso menu será assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<nav class="navbar navbar-default" role="navigation"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Navegação</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">CMS</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="{{ url('') }}">Home</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Artigos <b class="caret"></b></a> <ul class="dropdown-menu"> <li><a href="{{ url('artigos') }}">Lista</a></li> <li><a href="{{ url('artigos/inserir') }}">Adicionar</a></li> </ul> </li> </ul> </div> </div> </nav> |
Não vou explicar o código referente ao Bootstrap pois nosso foco é o Laravel. Você pode notar aqui a utilização do comando url() para criar os links. Este comando já criar o endereço completo e também permite que seja passado um parâmetro adicional que será incluído na URL, como o ID do item sendo editado por exemplo.
Outras Views
Vamos alterar nossas outras views. Primeiro mova as nossas 3 views (artigos, artigos_inserir e atigos_editar) para dentro do diretório views/artigos. Depois renomeie os arquivos:
- artigos.php para index.blade.php
- artigos_inserir.php para inserir.blade.php
- artigos_editar.php para editar.blade.php
Agora nossas views estão dentro de um subdiretório com o mesmo nome do nosso controller, artigos. Além disso renomeamos nossas views para que fiquem com o mesmo nome do método onde são utilizadas. Isso facilita a organização do nosso projeto.
index.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
@extends('layouts.padrao') @section('content') <h1> Artigos <small> @if ($artigos->count() === 1) Um artigo publicado @elseif ($artigos->count() > 1) {{ $artigos->count() }} artigos @else Nenhum artigo. @endif </small> </h1> <hr> {{-- Verifica se existem artigos --}} @if($artigos->count()) {{-- Imprimindo nossos artigos --}} @foreach ($artigos as $artigo) <div class="panel panel-default"> <div class="panel-heading"> <span class="glyphicon glyphicon-time"></span> {{ date('d/m/Y H:i', strtotime($artigo->created_at)) }} <div class="pull-right"> <div class="btn-group btn-group-xs"> <a href="{{ url('artigos/editar', $artigo->id) }}" title="Editar" class="btn btn-default">Editar</a> <a href="{{ url('artigos/remover', $artigo->id) }}" title="Remover" class="btn btn-default">Remover</a> </div> </div> </div> <div class="panel-body"> <h2>{{{ $artigo->titulo }}}</h2> <hr> <div> {{ $artigo->conteudo }} </div> </div> </div> @endforeach @else <h2>Nenhum artigo encontrado.</h2> @endif @stop |
Depois dessa alteração a nossa lista e artigos está assim:
inserir.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
@extends('layouts.padrao') @section('content') <h1>Inserir artigo</h1> <hr> {{ Form::open(array('url' => 'artigos/inserir', 'class' => 'form-horizontal', 'role' => 'form')) }} <div class="form-group"> <label for="titulo" class="col-lg-2 control-label">Título</label> <div class="col-lg-6"> {{ Form::text('titulo', '', array('class' => 'form-control', 'placeholder' => 'Título')) }} </div> </div> <div class="form-group"> <label for="conteudo" class="col-lg-2 control-label">Conteúdo</label> <div class="col-lg-6"> {{ Form::textarea('conteudo', '', array('class' => 'form-control', 'placeholder' => 'Conteúdo')) }} </div> </div> <div class="form-group"> <div class="col-lg-offset-2 col-lg-10"> {{ Form::submit('Salvar', array('class' => 'btn btn-primary')) }} <a href="{{ url('artigos') }}" title="Cancelar" class="btn btn-default">Cancelar</a> </div> </div> {{ Form::close() }} @stop |
Neste formulário substituímos as tags HTML pelos helpers do Laravel. Com eles conseguimos criar todas as tags necessárias para criar um formulário. O uso é opcional, mas eu recomendo a utilização do Form::open(), pois ele adiciona um campo HIDDEN chamado _token. Neste campo é inserido um string aleatória, que é verificada pelo Laravel no POST. Assim fica fácil bloquear pedidos de outros sites (CSRF – cross-site request forgery).
editar.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
@extends('layouts.padrao') @section('content') <h1>Editar artigo</h1> <hr> {{ Form::open(array('url' => 'artigos/editar', 'class' => 'form-horizontal', 'role' => 'form')) }} <div class="form-group"> <label for="titulo" class="col-lg-2 control-label">Título</label> <div class="col-lg-6"> {{ Form::text('titulo', $artigo->titulo, array('class' => 'form-control', 'placeholder' => 'Título')) }} </div> </div> <div class="form-group"> <label for="conteudo" class="col-lg-2 control-label">Conteúdo</label> <div class="col-lg-6"> {{ Form::textarea('conteudo', $artigo->conteudo, array('class' => 'form-control', 'placeholder' => 'Conteúdo')) }} </div> </div> {{ Form::hidden('id', $artigo->id) }} <div class="form-group"> <div class="col-lg-offset-2 col-lg-10"> {{ Form::submit('Salvar', array('class' => 'btn btn-primary')) }} <a href="{{ url('artigos') }}" title="Cancelar" class="btn btn-default">Cancelar</a> </div> </div> {{ Form::close() }} @stop |
Outros Arquivos
Como eu comentei do CSRF, vamos alterar nosso aquivo de rotas para filtrar pedidos incorretos. Vamos adicionar uma linha no arquivo app/routes.php:
1 2 3 4 5 6 7 8 9 10 |
// Validação CSRF Route::when('*', 'csrf', array('post')); Route::get('/', function() { return View::make('hello'); }); // Rota de artigos Route::controller('artigos', 'ArtigosController'); |
Com o comando Route::when() nós conseguimos filtrar pedidos usando um wildcard (*). Neste caso estamos “pegando” todos os pedidos, fazendo o filtro CSRF, de acordo com o tipo de pedido, neste caso o POST.
Vamos também alterar nosso controller. Precisamos modificar as views, pois modificamos o diretório das mesmas. Também vamos acrescentar a variável título onde precisamos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?php class ArtigosController extends BaseController { public function getIndex() { $artigos = Artigo::get(); return View::make('artigos.index', compact('artigos')); } public function getInserir() { $titulo = 'Inserir Artigo - Desenvolvendo com Laravel'; return View::make('artigos.inserir', compact('titulo')); } public function postInserir() { $artigo = new Artigo(); $artigo->titulo = Input::get('titulo'); $artigo->conteudo = Input::get('conteudo'); $artigo->save(); return Redirect::to('/artigos'); } public function getEditar($id) { $artigo = Artigo::find($id); $titulo = 'Editar Artigo - Desenvolvendo com Laravel'; return View::make('artigos.editar', compact('artigo', 'titulo')); } public function postEditar() { $artigo = Artigo::find(Input::get('id')); $artigo->titulo = Input::get('titulo'); $artigo->conteudo = Input::get('conteudo'); $artigo->save(); return Redirect::to('/artigos'); } public function getRemover($id) { $artigo = Artigo::find($id); $artigo->delete(); return Redirect::to('/artigos'); } } |
Conclusão
O Blade simplifica a criação das nossas views, fornecendo todas estruturas necessárias para uma boa programação. Não é recomendado utilizar lógica dentro da view, por isso você deve tentar não utilizar <?php dentro das views. Apenas em casos bem específicos você pode precisar das tags PHP diretamente na sua view. Um dos casos é se você precisa de uma variável de controle para uma repetição. Para iniciar uma variável ou atribuir, você vai precisar do <?php.
No artigo de hoje também incluímos o Bootstrap, que facilita na criação do design do nosso aplicativo. Eu recomendo a utilização do Bootstrap em projetos de sistemas, que geralmente não precisam de uma interface única. Mas tome cuidado ao utilizar em sites customizados pois pode ficar muito parecido com outros sites.
Se você encontrar algum erro ou estiver com alguma dificuldade, deixe um comentário. Para baixar o código atual, visite nosso repositório em https://github.com/oscardias/desenvolvendo_com_laravel.
Ola,
no ficheiro inserir.blade.php está
{{ Form::open(array('url' => 'artigos/editar', 'class' => 'form-horizontal', 'role' => 'form')) }}
e deveria estar:
{{ Form::open(array('url' => 'artigos/inserir', 'class' => 'form-horizontal', 'role' => 'form')) }}
Cumprimentos
Eu percebi o mesmo problema. Troquei lá e deu tudo certo. Parabéns pelo tutorial. Muito bem explicado, melhor do que qualquer documentação.
Abraços!
Valeu pela dica! Artigo e repositório atualizados.
Até pouco tempo atrás, era um reescrevedor de sites HTML para PHP, porém com as atualizações do PHP, resolvi aprender mais, eis que estou lendo muito sobre Frameworks, que facilitam o serviço, agilizam a programação.
Pergunta: Eu consigo criar um site completo usando um Framework? Em a resposta sendo positiva, como? e se a resposta for negativa, para que então usar o Framework?
Sim, você consegue criar um site completo usando um framework. Este tutorial que estou escrevendo tem como objetivo virar um CMS, e será criado usando o Laravel. Mas qual é teu objetivo quando voncerte as páginas HTML para PHP? Você adiciona alguma funcionalidade de CMS no site? Transforma elas em eCommerce?
O framework facilita principalmente quando você quer criar um aplicativo do zero, como um sistema de gestão de clientes por exemplo. Se você quer apenas transformar um site HTML em um CMS, pode utilizar o WordPress por exemplo. Vai facilitar sua vida porque você não vai precisar programar tudo do zero.
Boa tarde Oscar,
De antemão, parabéns pelas dicas.
Por favor, me ajude a entender essa questão: Quero configurar e validar um formulário com laravel, como tenho outras páginas, tenho que criar rotas e views para todas as páginas? Poderia usar o laravel apenas para a página de formulário?
Atenciosamente,
paulo Passic
Pelo que entendi você já tem um site pronto e quer apenas usar o laravel para validar um formulário, é isso?
Se você colocar todas as páginas dentro do laravel será necessário criar rotas para as páginas sim. Se não é necessário nenhuma lógica pode criar a rota apontando direto para as views, sem controllers. No futuro se você precisar aprimorar o site ficaria bem fácil pois já tem a estrutura do framework.
Outra possibilidade seria colocar o public do laravel dentro de um subdiretório do teu site e usar ele somente para este formulário. Por exemplo http://www.site.com.br/formulario.
Mas se você precisa apenas validar um formulário, porque não faz em PHP puro? Não vale a pena utilizar um framework somente para isso.
Abraço
https://www.facebook.com/groups/grupolaravel/
Parabéns!
Este conteúdo esclareceu todas as minhas dúvidas de uma forma clara e objetiva.
Obrigada,
Cissa.
Programadora
Subsecretaria de Informática
Prefeitura de Rio das Ostras – Rio de Janeiro
Prezado,
Sem dúvida um dos melhores tutoriais sobre Laravel.
Mas a minha duvida e a seguinte: Quando a aplicação com Blade cria a tela de login no dominio Entrar, a mesma nao aceita nenhum email e diz qua esta com email ou senha incorretos, daí nao consigo ir mais alem, pode me a judar?
Olá Denise,
Como assim não aceita nenhum e-mail? Qual erro que você recebe?
Verifique no código fonte da página (ou com o Inspecionar elemento) qual é o HTML que está sendo gerado. Deveria ser um INPUT com TYPE igual a “email” e NAME igual a “email” também.
Abraço
Ótimo artigo! É possível eu usar um template Bootstrap dentro de um blade que foi resultado de uma rota com parâmetro?
Exemplo:
Eu tenho uma lista de alunos e tenho uma opção de visualizar os dados completos de cada aluno, mas para isso é passado um ID na rota, tipo veraluno/{id}
Então a página que vejo os dados tem a seguinte url: veraluno/5
O número 5 seria o número do ID de um aluno.
Eu tenho um extends(‘template’) onde tenho a extensão de um template com o Bootstrap e funciona muito bem, mas quando exibe a página do aluno, esse template já não funciona, apresentando uma página crua apenas e os dados do aluno.
Tem como resolver isso? Não sei se consegui explicar bem.
Obrigado! =)