Laravel

Symfony Componentes: o que são e qual sua importância para o ecossistema PHP

Recentemente apresentei uma palestra no PHP Community Summit falando sobre o Ecossistema Symfony. A principal motivação para o conteúdo dessa palestra e também deste post é a importância que o Symfony possui para o ecossistema macro do PHP como um todo. Muito desta relevância do Symfony vem dos seus componentes, então vamos falar um pouco sobre eles.

O que são os componentes Symfony

A maioria das pessoas quando ouve falar a palavra Symfony logo pensa em um framework PHP. Na verdade, o Symfony é bem mais que isso, veja a definição oficial do site do Symfony:

O Symfony é um conjunto de componentes, um framework, uma filosofia e uma comunidade.

Antes mesmo de falar que Symfony é um framework existe uma ênfase nos componentes, mas o que são esses componentes. Se formos olhar novamente na definição oficial, mas agora sobre os componentes, teremos:

Componentes são pacotes reutilizáveis e desacoplados com objetivos específicos e que podem ser utilizados em qualquer aplicação PHP.

Exatamente nesse ponto entra a importância do Symfony para o PHP. Os componentes não estão acoplados e funcionam exclusivamente dentro do Symfony Framework, é possível usar os componentes em qualquer aplicação PHP.

Symfony - Fundamentos
Curso de Symfony - Fundamentos
CONHEÇA O CURSO

Quem utiliza os componentes do Symfony?

A maioria dos grandes projetos escritos em PHP utilizam algum dos diversos componentes do Symfony. Veja uma lista abaixo dos principais:

  • Laravel Framework
  • Drupal
  • Magento
  • Joomla
  • Yii Framework
  • API Platform
  • SDK PHP do facebook
  • SDK PHP do Google
  • PHPStan
  • Behat
  • Composer

A lista é muito grande! Na página do Symfony é possível verificar os projetos e quais componentes cada um utiliza. Uma coisa é certa, basicamente qualquer projeto PHP que vamos trabalhar utiliza algum tipo de componente do Symfony.

Porque tanta gente utiliza os componentes do Symfony

Nesse ponto deve estar se perguntando o que esses componentes fazem de especial para serem utilizados em tantos projetos importantes na linguagem PHP e aqui entram dois pontos bem importantes.

O primeiro ponto que leva muitos projetos a utilizarem os componentes do Symfony é a confiabilidade. Os componentes são testados e utilizados em milhares de projetos, além de possuírem uma comunidade por trás que realiza manutenções de segurança e melhorias regularmente.

O segundo ponto é a produtividade, ao invés de reinventar a roda e correr o risco que ela não fique tão redonda quanto o necessário, o que acaba sendo menos produtivo e mais arriscado, porque não utilizar a roda que já está pronta e testada.

O que esses componentes fazem

O Symfony possui componentes para diversos tipos de ações. Existem componentes que ajudam na estruturação de uma aplicação, por exemplo a estruturação de um framework. Existem componentes que ajudam em tarefas comuns a maioria das aplicações, por exemplo enviar email. E também existem componentes que são Polyfill para extensões e versões do PHP, por exemplo, vamos supor que sua aplicação necessite do PHP 7.3, porém não pode instalar essa versão em seu servidor, nesse caso pode instalar um componente que entregará as funções da versão sem realmente possuir.

Alguns exemplos de componentes para estruturação de uma aplicação:

  • HTTP Kernel – Responsável por ajudar na estruturação desde o processo de request até o retorno da Response;
  • HTTP Foundation – Permite acesso a uma implementação orientada a objetos do protocolo HTTP;
  • Routing – Facilita o trabalho de roteamento da aplicação;
  • DependencyInjection – Implementa o container e recursos de injeção de dependência
  • Config – Facilita o acesso às configurações;
  • Dotenv – Permite o acesso às variáveis de ambiente;

Alguns componentes que realizam tarefas comuns a maioria das aplicações:

  • Mailer – Envio de email usando diversos serviços de forma extremamente simples;
  • HTTP Client – Permite realizar requisições HTTP a outras aplicações;
  • Form – Facilita a criação e a recuperação dos dados enviados via formulário;
  • Validation – Permite a validação de dados usando regras predefinidas ou através da criação de novas regras;
  • Security – Facilita o trabalho de autenticação e autorização na aplicação;
  • Cache – Facilita a utilização de cache com diversos meios de armazenamento;
  • DomCrawler – Possui mecanismos que permite navegar em documentos HTML e XML.

Temos também os componentes de polyfill:

  • Polyfill PHP 5.4 até 7.3
  • Polyfill XML
  • Polyfill Intl
  • Polyfill Mbstring
  • Polyfill Ctype

Sempre que for usar componentes de polyfill é necessário consultar a documentação para verificar quais funções o componente realmente implementa, pois nem todas podem estar disponíveis.

Porque não utilizar os componentes do Symfony

Nem tudo são rosas, como a maioria das coisas também existem pontos negativos ao usar componentes prontos.

Podemos citar primeiramente a falta de liberdade. Se sua aplicação necessita de uma nova função que não possui no componente. Caso queira implementar no componente oficial terá que convencer a equipe mantenedora que sua nova funcionalidade é importante para a maioria das pessoas que utilizam o componente, além de ter que seguir todas as regras para contribuir no projeto.

Outro ponto é a dependência do componente. A aplicação pode ficar dependente de um componente de tal forma que se ele for descontinuado ela esteja em risco. Por outro lado, isso pode ser contornado com a arquitetura correta da sua aplicação, se ao invés de depender diretamente do componente, depender de contratos, será possível trocar de componente com o mínimo de esforço.

Conclusão

O Symfony possui mais de 50 componentes para os mais diversos propósitos. Aconselho acessar a lista de componentes e ler o que cada um deles realiza. Desse modo sempre que tiver uma situação onde é necessário implementar uma nova funcionalidade na sua aplicação, poderá considerar um componente Symfony analisando as vantagens e desvantagens discutidas aqui.

Principais métodos para obtenção de parâmetros da Request no Laravel

Nesse artigo vamos ver como obter os dados enviados pelo usuário no Laravel. Na verdade, quando falamos em pegar dados enviados pelo usuário, seja via formulário ou diretamente na URL, estamos falando da Request. Caso não saiba o que é Request temos esse artigo que fala sobre alguns conceitos HTTP.

O Laravel possui uma classe específica para trabalhar com os dados enviados na requisição. Essa classe tem o nome de Request e fica no namespace \Illuminate\Http. Ela possui uma série de métodos que facilitam obtenção das informações enviadas pelo cliente.

PHP Básico
Curso de PHP Básico
CONHEÇA O CURSO

Como podemos utilizar a classe Request

Geralmente o local onde mais usamos os dados enviados na requisição é o Controller. No Laravel, podemos injetar instâncias diretamente nos métodos do controller, isso nos permite usar facilmente a instância da classe Request.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function store(Request $request)
    {
        //Usamos a instância para chamar os métodos da requisição
        $request->...();
    }
}

Obtendo dados enviados via URL

O modo mais simples de enviar informações do usuário para o servidor através da requisição é a URL. Usando um padrão específico podemos passar dados no formato chave valor, veja a URL abaixo:

http://servidor.test/meurecurso?escola=Treinaweb&curso=Laravel

Através dela estamos passando os parâmetros escola e curso que possuem respectivamente os valores TreinaWeb e Laravel.

Para obter todos os dados passados na URL usamos o método query sem passar nenhum parâmetro $request-&gt;query(). O Laravel pega todos os parâmetros e retorna em forma de array:

array:2 [
  "escola" => "Treinaweb"
  "curso" => "Laravel"
]

O método query pode ser usado para obter apenas um valor, basta passar o nome da chave no primeiro argumento. Caso a chave não esteja declarada na URL ainda é possível definir um valor padrão no segundo argumento.

$request->query("escola");
$request->query("escola", "Valor padrao");

Montando o formulário de exemplo

Os dados enviados via POST estão localizados no corpo da requisição. O Laravel possui alguns métodos que nos permitem obter essas informações para serem usadas na nossa aplicação.

Para conseguirmos enviar informações via POST precisamos criar um formulário que será submetido para uma rota qualquer da nossa aplicação. Vamos usar como base o seguinte formulário:

<form action="http://servidor.test/meurecurso" method="POST">
    {{ csrf_field() }}
    Nome <input type="text" name="name" value="Elton"> <br>
    Idade <input type="text" name="age" value="27"> <br>
    Email<input type="text" name="email" value="elton.fonseca@treinaweb.com.br"> <br>
    <input type="submit" value="Enviar">
</form>

OBS: o helper csrf_field retorna um input do tipo hidden com o token que confirma que o formulário está sendo realmente enviado pela nossa aplicação.

Obtendo dados enviados via POST

O primeiro método que vamos falar é o all() ele retorna todos os dados em formato de array:

array:3 [
  "name" => "Elton"
  "age" => "27"
  "email" => "elton.fonseca@treinaweb.com.br"
]

Outro método que podemos usar é o input. Ele retorna um único valor e podemos definir um valor padrão como segundo argumento, caso a chave não seja encontrada:

$request->input('name');
$request->input('name', 'Nome padrão');

Temos também os métodos only que busca apenas os parâmetros especificados nele e o método except que trás todos parâmetros, exceto os especificados nele. Podemos passar uma lista de argumentos ou um array:

$request->only('name', 'email');
$request->only(['name', 'email']);
$request->except('age');
$request->except(['age']);

Todas as chamadas acima retornam a mesma informação:

array:2 [
  "name" => "Elton"
  "email" => "elton.fonseca@treinaweb.com.br"
]

Uma observação importante! Todos os métodos que vimos nesse tópico all(), input(), only() e except() pegam valores passados via POST e também via GET na URL, dando preferência para os parâmetros POST quando eles possuem o mesmo nome. Enquanto o query, que vimos no tópico anterior, pega apenas os parâmetros passados via GET.

Laravel - Framework PHP (Parte 1/3)
Curso de Laravel - Framework PHP (Parte 1/3)
CONHEÇA O CURSO

Propriedade dinâmica

O Laravel cria propriedades dinamicamente para os parâmetros enviados na requisição, essas propriedades facilitam o acesso aos dados e torna o código mais limpo.

$request->name;  //Treinaweb
$request->age;   //27
$request->email; //elton.fonseca@treinaweb.com.br

É possível obter dinamicamente os parâmetros enviados via GET e POST.

Helper request

Existem algumas situações onde precisamos usar os dados da requisição em locais onde não temos fácil acesso a instância da requisição, nesses casos podemos usar o helper request. Quando chamamos o helper sem passar nenhum argumento ele retorna uma instância da classe request, a partir dela podemos chamar qualquer método da Request:

request()->all();
request()->input("name");
request()->only("email");
//...

Ainda é possível pegar os dados do parâmetro passando o nome do argumento e o valor padrão, para caso o parâmetro não seja encontrado:

request("name", "Nome padrão");

Verificando o parâmetro

Outra situação comum é precisarmos verificar se um parâmetro foi passado na requisição. Para isso usamos o método has(). Ele retorna verdadeiro independente do valor passado, mesmo que o valor seja vazio:

if ($request->has('name')) {
    //
}

Caso precise verificar se o parâmetro foi passado na requisição e não é vazio, podemos usar o método filled():

if ($request->filled('name')) {
    //
}

Obter arquivo e realizar upload

O Laravel possui um método especial chamado file para obter os arquivos. Também é possível usar as propriedades dinâmicas:

$request->file('image');
$request->image;

Esse método retorna uma instância da classe Illuminate\Http\UploadedFile, ela já possui todos os recursos necessários para salvar o arquivo de maneira simples. Podemos simplesmente chamar o método store para salvar o arquivo:

$request->file('image')->store('local');

Conclusão

Nesse post nós vimos os principais métodos para obtenção de parâmetros enviados pelo usuário através da requisição. Além desses dados a requisição ainda possui diversas outras informações que são enviadas pelo cliente da nossa aplicação. A documentação do Laravel possui vários exemplos práticos de como obter esses dados.

O que é Laravel?

O Laravel é um dos Frameworks PHP mais utilizado no mercado.

Caso você não saiba:

Um framework é um facilitador no desenvolvimento de diversas aplicações e, sem dúvida, sua utilização poupa tempo e custos para quem o utiliza, pois de forma mais básica, é um conjunto de bibliotecas utilizadas para criar uma base onde as aplicações são construídas, um otimizador de recursos. Tem como principal objetivo resolver problemas recorrentes com uma abordagem mais genérica. Ele permite ao desenvolvedor focar nos “problemas” da aplicação, não na arquitetura e configurações.

Aqui no blog também temos um artigo bem legal sobre: Para que serve um Framework?

História do Laravel

Desenvolvido por Taylor B. Otwell, tendo sua primeira versão beta lançada em meados de Junho de 2011, o Laravel é um Framework Open Source sob a licença MIT, criado com o propósito de ser uma alternativa mais avançada do CodeIgniter. Atualmente, se encontra na versão 5.8, tendo seu código-fonte hospedado no GitHub.

Recursos do Laravel

Dentre os diversos recursos do Laravel, podemos citar como principais:

  • Sistema de template (Blade)

O Laravel possui um sistema de template que facilita a criação da camada de visualização de dados (Páginas HTML). Com ele, podemos facilmente criar páginas simples e intuitivas de forma rápida e eficaz. Dentre alguns dos recursos do Blade, se destacam: Herança de layouts, sistema de tags, seções e uso de código PHP nos templates.

  • Módulo de autenticação

O Laravel possui, por padrão, um módulo de autenticação/autorização completo que provê todos os recursos para sua implementação, como: Autenticação de usuários, autorização de usuários, recuperação de senhas, logout, controle de sessão e cadastro de usuários.

  • Eloquent ORM

Com o Laravel não precisamos criar códigos SQL para manipular ou criar tabelas no Banco de Dados. Todo processo é feito utilizando código PHP que, posteriormente, será convertido em instruções SQL. Implementa o padrão Active Record, onde cada model da aplicação representa uma tabela no banco de dados.

Desenvolvedor Laravel Full-Stack
Formação: Desenvolvedor Laravel Full-Stack
Nesta formação você aprenderá desenvolver aplicações PHP usando o framework Laravel com maestria. Ao final desta formação, você terá condições de trabalhar em grandes aplicações web ou APIs integradas com diversos serviços, tudo isso utilizando as melhores práticas do mercado.
CONHEÇA A FORMAÇÃO

Padrão MVC

O Laravel utiliza o padrão MVC (Model, View e Controller) que, basicamente, funciona da seguinte forma:

  • Model é a camada responsável pela parte lógica da aplicação, ou seja, todos os recursos da sua aplicação (consultas ao BD, validações, notificações, etc), mas ele não sabe quando isso deve ser feito, a camada de model apenas tem o necessário para que tudo aconteça, mas não sabe quando irá executar.

  • View é a camada responsável por exibir dados para o usuário, seja em páginas HTML, JSON, XML, etc. A camada View não possui responsabilidade de saber quando vai exibir os dados, apenas como irá exibi-los.

  • Controller é o famoso “meio-de-campo” da aplicação. Essa é a camada que sabe quem chamar e quando chamar para executar determinada ação.

Basicamente, o MVC funciona da seguinte forma:

Ao receber uma requisição, o Controller solicita ao Model as informações necessárias (que virão do banco de dados), que as obtém e retorna ao Controller. De posse dessas informações, o Controller as envia para a View que irá renderizá-las.

Vantagens em utilizar o Laravel

  • Simples e fácil;
  • Documentação completa;
  • Amplamente utilizado;
  • Comunidade ativa;
  • Gratuito.

Concluindo:

O Laravel é um excelente Framework para desenvolvimento de aplicações web. Neste artigo vimos algumas de suas principais características e funcionalidades, o que o torna uma excelente escolha para a criação dos seus projetos.

Como melhorar o retorno das suas APIs no Laravel com API Resource do Eloquent

Quando estamos construindo uma API, alguns pontos são extremamente importantes para que o cliente consiga consumir corretamente as informações. Um desses pontos é o modo como retornamos dados da nossa API.

Em aplicações web existe uma preocupação muito grande com a aparência e usabilidade na hora de mostrar as informações. Quando estamos trabalhando com APIs nossa preocupação não deve ser diretamente ligada a esses detalhes, porém precisamos cuidar de outras características para que os clientes da nossa API consigam utilizá-la de maneira correta. Um desses cuidados deve ser a estrutura que as informações são retornadas.

Como os dados são transferidos em uma API

Geralmente as APIs são utilizadas para integração entre sistemas diferentes. Esses sistemas podem apresentar arquiteturas completamente distintas, por esse motivo os dados são transferidos para um formato intermediário conhecido tanto pela API quanto pelo cliente. Os formatos mais utilizados são JSON, XML e YAML.

O processo de transformação dos dados para esse formato intermediário normalmente é chamado de serialização. No Laravel temos recursos bem importantes para serialização, aconselho a leitura do post onde falamos o que é e como utilizar serialização JSON no Laravel. O grande detalhe é que mesmo com os recursos específicos que a serialização possui ele não permite personalizar totalmente a resposta, nesse ponto entra o API Resource.

Laravel - Eloquent ORM
Curso de Laravel - Eloquent ORM
CONHEÇA O CURSO

O que é API Resource

O API Resource é uma camada extra que usamos na API para transformar os dados que vamos enviar ao cliente. Ela permite que a estrutura de retorno seja totalmente personalizada, isso nos permite formatar os dados na melhor maneira para entregar ao cliente. Além de garantir o desacoplamento com o model, uma vez que podemos definir a estrutura de forma separada.
O conceito da camada de transformação não é exclusividade do Laravel. Inclusive no próprio PHP temos algumas outras bibliotecas que facilitam esse trabalho, uma das mais conhecidas é o Fractal. O API Resource do Laravel facilita bastante a vida quando estamos dentro do Framework, mas também é possível utilizar qualquer outra biblioteca.

Resource

O primeiro conceito que precisamos conhecer é o resource. Ele é uma classe que usamos para transformar um único item de um recurso. Falando assim parece um pouco complicado, mas na prática o que ele faz é pegar um item que precisamos converter e transformar para o formato especificado nele. Vamos imaginar que estamos buscando o produto Iphone X no banco de dados e precisamos devolver ele na API com uma formatação específica, é basicamente isso que o Resource faz.

A classe do resource deve possuir um método chamado toArray, esse método precisa retornar um array com os dados que deseja que o recurso possua após a conversão. O Laravel injeta automaticamente as propriedades do nosso model no resource, isso nos permite acessá-las através do escopo this. Veja o exemplo abaixo:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ProductResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'codigo' => $this->id,
            'nome'   => $this->name,
            'preco'  => $this->price,
        ];
    }
}

Basicamente o que estamos fazendo é pegar os dados vindos do model (id, name e price) e colocando respectivamente nos itens do array (código, nome e preco).

O modo como usamos o resource é extremamente simples, basta passarmos 1 item do model no construtor da classe:

new App\Http\Resources\ProductResource(App\Product::find(10));

A instância acima pode ser retornada diretamente em uma action do controller ou em uma rota que utiliza função anônima.

A classe acima parece não fazer muito sentido olhando à primeira vista, porém ganhamos algumas vantagens imprescindíveis em usar essa camada:

  • Liberdade para definição da estrutura
  • Possibilidade de enviar dados extras, como, relações ou gerados através de outros métodos da aplicação
  • Podemos alterar o nome das propriedades do nosso model sem problemas, pois agora definimos o nome que será retornado ao usuário diretamente na estrutura;
  • O nosso model não está preso a somente um modo de exibição, caso necessário podemos criar várias classes de Resource para o mesmo model.
Laravel - Eloquent ORM
Curso de Laravel - Eloquent ORM
CONHEÇA O CURSO

Resource Collection

A classe que vimos acima é usada para conversão de apenas um item do model. É comum, porém, precisamos retornar uma coleção de itens na nossa API. Nesse caso utilizamos o Resource Collection. Ele é muito útil para retornar meta informações sobre o conjunto de dados que estamos retornando.
Nele também usamos o método toArray para montar o retorno da nossa aplicação. E usamos a propriedade collection para retornar as informações da coleção:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class ProductCollection extends ResourceCollection
{
    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'links' => [
                'self' => 'link-value',
            ],
        ];
    }
}

O modo de usar é basicamente igual ao Resource, porém precisamos passar um conjunto de informações:

new App\Http\Resources\ProductCollection(App\Product::all());

Os dados buscados no banco serão colocados dentro da chave data do nosso resultado. O Laravel automaticamente utiliza o Resource específico para converter cada item da coleção com base na convenção do nome, com isso terá a estrutura definida tanto para cada item específico da coleção como da estrutura geral de retorno.

Conclusão

O modo como retornamos as informações na nossa API é um dos itens mais importantes. Isso juntamente com o uso correto e semântico HTTP dos verbos na requisição e dos códigos na resposta são os itens onde os desenvolvedores mais pecam e que precisa de atenção no desenvolvimento de APIs. Não deixe também de explorar um pouco a documentação do API Resouce no site do Laravel, ele possui recursos para ajudar com relações, meta informações, personalização da resposta HTTP entre outros.

Conhecendo os recursos de serialização JSON do Laravel

Imagina que compramos uma barraca de acampar e ao chegar em casa montamos. Provavelmente não vamos conseguir carregar a barraca montada, por esse motivo desmontamos, transportamos e depois realizamos a montagem novamente. Quando estamos falando de programação em algumas situações precisamos realizar basicamente o mesmo processo. Em ciência da computação geralmente chamamos de serialização o ato de converter uma estrutura de dados para um formato de transporte ou armazenamento que pode ser reconstruído depois.

Quando trabalhamos com desenvolvimento de APIs é comum precisarmos serializar para o formato no qual eles serão transportados. Na maioria dos casos as APIs utilizam o formato JSON, porém pode ser qualquer outro como XML ou YAML.

Ao falarmos de serialização o Laravel possui algumas características que nos ajuda a realizar a serialização de forma automática e recursos que nos permite personalizar os dados na serialização.

Laravel - Desenvolvimento de APIs REST
Curso de Laravel - Desenvolvimento de APIs REST
CONHEÇA O CURSO

Serialização automática no Controller

Alguns frameworks como Symfony esperam que o retorno de um método do controller seja sempre uma instância da classe response, contudo no caso do Laravel isso é um pouco diferente. Quando retornamos qualquer estrutura iterável em um controller automaticamente ele tenta serializar para JSON e enviar na resposta. Inclusive ele indica no cabeçalho da resposta que estamos retornando application/json.

Faça um teste retornando um array simples ou mesmo o resultado de uma busca com Eloquent:

public function action()
{
    return ["Escola" => "Treinaweb Cursos"];
}

Ao acessar terá:

Mesma coisa também acontece se retornarmos o resultado de uma consulta no banco de dados com Eloquent:

public function action()
{
    return AppProduct::all();
}

Serialização manual

O Laravel também nos permite serializar os dados manualmente. Basta chamarmos o método toJson em uma collection. Como os models do Eloquent sempre retornam uma collection quando buscamos por mais de um registro, podemos trabalhar do seguinte modo:

$products = AppProduct::all();

$json = $products->toJson();

Um detalhe importante! Quando fazemos a serialização o resultado é uma string simples com uma marcação no formato JSON. No caso acima, se retornarmos a variável $json em um controller o content-type será text/html. O correto então é montar a resposta informando manualmente que estamos retornando um application/json.

Escolhendo os dados que não serão serializados

Muitas vezes não podemos retornar todos os dados do nosso model para a resposta. Imagine que o produto tem um campo preço de custo, não é nada legal enviar isso para um revendedor, por exemplo.

Nesses casos podemos declarar um atributo no model informando quais propriedades não devem ser incluídas quando realizarmos a serialização:

<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Product extends Model
{
    /**
     * Atributos que não serão serializados
     *
     * @var array
     */
    protected $hidden = ['cost'];
}

Se por algum motivo em uma serialização específica quiser usar um dos campos escondidos temos um método específico:

$product->makeVisible('cost')->toJson();

Escolhendo os dados que serão serializados

Ao contrário temos também o atributo que indica apenas os campos que serão usados na serialização:

<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Product extends Model
{
    /**
     * Atributos que serão serializados
     *
     * @var array
     */
    protected $visible = ['id', 'name', 'price'];
}

Podemos usar um método para esconder as propriedades que estão nessa lista:

return $product->makeHidden('price')->toJson();

Outros recursos

Outros dois recursos podem ajudar muito dependendo da situação. O primeiro nos permite usar um acessor na serialização, basta indicarmos o nome dele no atributo appends do model. Além disso podemos formatar propriedades do tipo data com atributo casts.

Como colocar uma aplicação Laravel em produção e automatizar o processo de deploy

O Laravel é um dos frameworks mais falados da web. Existem milhares de posts na internet ensinando como fazer basicamente tudo, porém, até hoje pouco vi falar sobre uma coisa simples: o que precisamos fazer para colocar uma aplicação de forma correta em produção.

Laravel - Framework PHP (Parte 1/3)
Curso de Laravel - Framework PHP (Parte 1/3)
CONHEÇA O CURSO

Configurando o .env

No arquivo .env colocamos as configurações do ambiente específico que vamos rodar a aplicação. Em ambiente de produção dois itens desse arquivo devem obrigatoriamente ser alterados para a segurança da aplicação:

APP_ENV=production
APP_DEBUG=false

O APP_ENV informa qual o nome do ambiente que estamos executando a aplicação. O aconselhável em produção é definir o valor production. Isso porque o Laravel tem uma serie de proteção quando ele está configurado assim. Veja por exemplo o que acontece se tentarmos rodar as migrations com essa diretiva em produção:

rodar migrations em producao

O APP_DEBUG indica para o Laravel se ele deve mostrar erros no navegador. Exibir informações de erro é extremamente perigoso, um usuário mal intencionado pode obter diversas informações a partir dele. Por esse motivo sempre devemos deixar como false, assim ele mostrará apenas a mensagem informando que aconteceu algo de errado:

Mensagem de erro para o usuário laravel

Se precisar saber quais erros estão acontecendo em produção pode verificar o arquivo de log do Laravel.

Laravel - Framework PHP (Parte 2/3)
Curso de Laravel - Framework PHP (Parte 2/3)
CONHEÇA O CURSO

Instalando as dependências

Ao clonar a aplicação para nosso servidor de produção, a primeira coisa que precisamos fazer é executar o composer para baixar as dependências do projeto. Quando estamos em produção podemos passar dois parâmetros extras, veja como fica o comando:

composer install --optimize-autoload --no-dev

–optimize-autoload: gera uma versão das regras do PSR-4/PSR-0 em um arquivo PHP único, evitando que a linguagem tenha que o olhar no sistema de arquivos. Esse arquivo de classmap pode ser facilmente cacheado pelo opcache tornando a obtenção dos caminhos muito mais rápido. Mais detalhes em autoloader-optimization

–no-dev: ignora as dependências exclusivas do ambiente de desenvolvimento

Cacheando os arquivos de configuração

Acessar o arquivo .env toda hora é muito custoso, uma vez que ele é um arquivo de texto e não pode ser cacheado pelo opcache. Baseado nisso, o Laravel possui um comando que copia as configurações dele para um arquivo php único diminuindo assim o custo de acesso. Para isso temos o comando:

php artisan config:cache

Único detalhe que devemos ficar atentos quando executamos esse comando. Como as configurações do arquivo de configuração .env são carregados para o arquivo único, não é aconselhável usar o helper env() do Laravel que pega as configurações do arquivo .env já que ele pode não ser carregado.

Cacheando as rotas

O Laravel possui um comando que serializa todas as rotas da aplicação. Esses dados são passados para um único método em um arquivo cacheado. Isso diminui o tempo de carregamento das rotas da aplicação:

php artisan route:cache

O comando acima só funciona se não houver nenhuma chamada de função anônima nos arquivos de rota. A chamada de funções anônimas no arquivo de rota não é uma boa prática por padrão, o cache de rotas é mais um motivo para não usarmos.

Laravel - Framework PHP (Parte 3/3)
Curso de Laravel - Framework PHP (Parte 3/3)
CONHEÇA O CURSO

Outro processos

Essas são alguma práticas que podemos adotar na hora de realizar o deploy da nossa aplicação. Muitas outras podem ser aplicadas no seu deploy, como, rodar o Laravel Mix ou algum outro automatizador de tarefas, executar testes e outros detalhes.

Veja abaixo de forma prática alguns modos de automatizar os processos mostrados nesse post:

Como se usa e o que resolve o recurso de Route Model Binding do Laravel

O Route Model Binding não é um recurso novo no Laravel, porém, o pessoal que está começando no framework costuma ter dificuldade em entender qual problema ele resolve e como ele funciona.

Ele existe desde a versão 4.2 do Laravel e de lá para cá já passou por algumas pequenas mudanças e da versão 5.2 em diante não teve mais o modo de usar alterado, com isso podemos chegar à conclusão de que ele alcançou uma boa maturidade.

Qual problema o Route Model Binding tenta resolver?

Antes de falarmos o que é o recurso, é importante sabermos qual problema ele resolve. É muito comum em aplicações web recebermos a partir da URL o código de um registro que vamos precisar realizar uma ação no banco de dados. Veja abaixo alguns exemplos:

http://meusistema.dev/produto/1/mostrar
http://meusistema.dev/produto/1/editar
http://meusistema.dev/produto/1/atualizar
http://meusistema.dev/produto/1/deletar

No caso acima o número 1 representa o código do produto que desejamos realizar determinada ação. Pensando no nosso código, dentro de cada uma dessas ações precisaremos buscar o registro com código 1 no banco de dados. Mas, e se baseado nesse código o próprio framework já buscasse esse registro no banco de dados e injetasse ele prontinho para ser usado, evitando a repetição de código desnecessário? É exatamente isso que o Route Model Binding faz!

Como o Laravel faz isso?

O Laravel faz isso usando o parâmetro na rota e um model do Eloquent. Veja a explicação baseado no nome do recurso:

  • Route: utiliza o nome do parâmetro especificado na rota para saber qual recursos ele deve usar;
  • Model: utiliza o model injetado na ação para realizar a busca baseado no valor passado na rota;
  • Bind: faz o bind entre o parâmetro passado na rota e a variável injetada na ação.

Esse processo por padrão é feito implicitamente, basta passar o nome do parâmetro, o model que será usado e o nome da variável que receberá a instancia do model. Existem situações onde não é possível fazer isso de forma automática, pois o valor passado na URL precisa ser filtrado de um modo diferente e não baseado na chave padrão. Nesse caso podemos fazer esse filtro explicitamente.

Implicit Binding

No modo implícito o próprio Laravel faz todo trabalho automaticamente, entregando a instância do model já corretamente populada. Se o valor passado na URL não for encontrado no banco de dados, o Laravel retorna um erro de página não encontrada, evitando assim que a execução chegue se quer à ação.

Primeira coisa que precisamos fazer é declarar o parâmetro na rota:

Route::get('products/{product}', 'ProductController@edit');

Agora, na ação do controller, basta injetarmos o model referente ao produto:

/**
 * Show the form for editing the specified resource.
 *
 * @param  \App\Product $product
 * @return \Illuminate\Http\Response
 */
public function edit(Product $product)
{
    //aqui temos o produto já filtrado na variável $product
}

Alguns detalhes importantes para evitar problemas na hora de usar o recurso:

1) O nome do parâmetro passado na rota deve ser o mesmo nome da variável injetada da ação:

//nome do parâmetro product
Route::get('products/{product}', 'ProductController@edit');

//injeção na ação
public function edit(Product $product)

2) Se quiser alterar o nome da variável precisa alterar também o nome do parâmetro e vice-versa;

3) Também deve sempre se atentar se está usando a classe correta do model na injeção do método da ação.

Explicit Binding

Existem situações onde nem tudo segue as regras para realização do bind automático. Nesse caso, podemos informar para o framework como fazer o Route Model Binding manualmente.

Essa lógica pode ser criada dentro do método boot em um service provider qualquer. Veja o exemplo abaixo:

Route::bind('product', function ($value) {
    $id = decode($value); 

    return \App\Product::where('id', $id)->first() ?? abort(404);
});

No exemplo acima estamos usando uma função hipotética chamada decode que decodifica o valor passado na URL para o ID valido do banco de dados. Poderia usar qualquer outra lógica, como filtrar por outro campo e etc.

Veja como fica essa configuração usando o RouteServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * This namespace is applied to your controller routes.
     *
     * In addition, it is set as the URL generator's root namespace.
     *
     * @var string
     */
    protected $namespace = 'App\Http\Controllers';

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        Route::bind('product', function ($value) {
            $id = decode($value); 

            return \App\Product::where('id', $id)->first() ?? abort(404);
        });
    }

    /**
     * Define the routes for the application.
     *
     * @return void
     */
    public function map()
    {
        $this->mapApiRoutes();

        $this->mapWebRoutes();

        //
    }

    /**
     * Define the "web" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     *
     * @return void
     */
    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

    /**
     * Define the "api" routes for the application.
     *
     * These routes are typically stateless.
     *
     * @return void
     */
    protected function mapApiRoutes()
    {
        Route::prefix('api')
             ->middleware('api')
             ->namespace($this->namespace)
             ->group(base_path('routes/api.php'));
    }
}

Conclusão

Esse é mais um recurso do Laravel que nos ajuda a tornar nosso controllers muito mais limpos, legíveis e fáceis de realizar manutenção. Além de tudo isso, ele permite personalizar totalmente a lógica na hora de filtra o registro, o que o torna muito flexível.

Usando escopos do Eloquent para construir consultas mais limpas no Laravel

É comum precisarmos por diversas vezes fazer consultas que envolvam o mesmo trecho de código. Pensando nisso, o Eloquent possui os escopos, que permitem aplicar modificadores nas consultas. Esses modificadores podem ser aplicados em dois níveis ao model: local e global.

Laravel - Framework PHP (Parte 1/3)
Curso de Laravel - Framework PHP (Parte 1/3)
CONHEÇA O CURSO

Escopo local

O escopo local permite criar métodos com modificadores. Esses métodos podem ser aplicados a uma consulta como se fossem métodos próprios do Eloquent.

Vamos supor que em um model chamado Client exista uma coluna limit que indica o limite de compra do cliente. É possível imaginar que diversas vezes no projeto precisaremos buscar clientes que possuam limite maior que 0.

Poderíamos ter como exemplo as seguintes consultas:

1) Buscar por nome dos clientes que possuem limite:

Client::where('limit', '>', 0)->where('name', 'like', $nome)->get();

2) Buscar por cidade dos clients que possuem limite:

Client::where('limit', '>', 0)->where('city', $cidade)->get();

Note que repetimos o mesmo código where('limit', '>', 0) nas duas consultas. Isso pode não ser muito bom pois, caso a regra de negocio mude, será necessário alterar dentro de cada local do projeto.

A criação de um escopo pode resolver o problema acima facilmente. Para criar um novo escopo basta definir um método publico na classe do model, ele deve ter o nome no padrão scopeNomeEscopo e receber um parâmetro que contém a instancia do Builder.

Veja o exemplo de escopo para definir o limite > 0:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Client extends Model
{
    /*
     * Escopo que busca clientes com limite
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeHasLimit($query)
    {
        return $query->where('limit', '>', 0);
    }
}

Agora podemos usar o escopo facilmente na consulta como se fosse um método do próprio Eloquent:

Busca por nome dos clientes que possuem limite:

Client::hasLimit()->where('name', 'like', $nome)->get();

Busca por cidade dos clients que possuem limite:

Client::hasLimit()->where('city', $cidade)->get();

À primeira vista, parece não ter muita diferença, mas já ganhamos na legibilidade da leitura das consultas, quantidade de código digitado e também na definição única do código.

Vamos supor que agora ao invés de 0 o limite deve ser maior que 100 e que precise também sempre ordenar pelo maior limite. Provavelmente você ficaria muito feliz em precisar alterar em apenas um local ao invés de vários, além de ter que ficar olhando cada consulta para conferir se está tudo certo.

Escopo global

O escopo global é muito útil quando necessário aplicar um modificador a todos os registros que forem buscados no model. Ao invés de definirmos em cada consulta os modificadores, ou até mesmo criar escopos locais e aplicar em cada consulta, podemos declarar o escopo global.

Vamos supor devemos mostrar apenas clientes ativos e que eles sejam ordenados pela data de cadastro. Podemos adicionar dois escopos:

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class Client extends Model
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        //filtra apenas por clientes ativos
        static::addGlobalScope('active', function (Builder $builder) {
            $builder->where('active', true);
        });

        //ordena pela data de cadastro
        static::addGlobalScope('created', function (Builder $builder) {
            $builder->orderBy('created_at');
        });
    }
}

Agora, toda vez que consultar os clientes automaticamente esses dois modificadores são aplicados.

Consulta sem utilizar o escopo global

Caso não queira aplicar em uma consulta especifica basta chamar o método withoutGlobalScopes():

Client::withoutGlobalScopes()->get();

Se quiser deixar de aplicar apenas um escopo global especifico, basta passar o nome dele:

Client::withoutGlobalScope('created')->get();

Escopo global usando classe própria

É possível também passar uma classe ao invés de uma função anônima para o método addGlobalScope():

static::addGlobalScope(new \App\Scopes\ActiveScope);

Nesse caso a classe para aplicar a condição de ativo ao cliente fica:

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class ActiveScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('active', true);
    }
}

Conclusão

O uso de escopo nos ajuda na legibilidade das nossas buscas e torna o código menos repetitivo. Se aplicado de maneira correta, ele pode ajudar bastante na qualidade do código e facilitar futuras manutenções.

Laravel - Framework PHP (Parte 2/3)
Curso de Laravel - Framework PHP (Parte 2/3)
CONHEÇA O CURSO
Laravel - Framework PHP (Parte 3/3)
Curso de Laravel - Framework PHP (Parte 3/3)
CONHEÇA O CURSO

Removendo a lógica das views com presenters no Laravel

Um dos problemas mais clássicos de aplicações que utilizam MVC é a camada de view concentrar lógica ao invés de apenas aspectos relacionados à exibição. Veremos nesse artigo como isso pode ser contornado.

Frameworks como Laravel e Symfony utilizam por padrão template engines como Blade e Twig, respectivamente. Esses template engines possuem o intuito de diminuir a complexidade das views, no entanto, nem mesmo com essa ajuda as views ficam limpas o suficiente. Existem certos tratamentos que acabam sobrecarregando as views e também não é papel do model tratar isso. É nesse ponto que entram os Presenters.

Com intuito de ajudar na solução desses problemas podemos usar essa camada extra nas nossas aplicações. O principal objetivo dela é facilitar e devolver a informação já tratada para a view, diminuindo assim a quantidade de decisões que precisamos tomar dentro de nossas views e eximindo também os models de uma responsabilidade que não é deles.

Laravel - Framework PHP (Parte 1/3)
Curso de Laravel - Framework PHP (Parte 1/3)
CONHEÇA O CURSO

Escolhendo e instalando um Presenter

Por padrão o Laravel não possui uma camada de Presenter, precisamos instalar via Package. Existem diversos packages que fazem esse processo, alguns mais elaborados e outros mais simples. No caso do nosso exemplo vamos usar o desenvolvido por Jeffrey Way disponível aqui.

Basta executar o comando para o composer adicionar a dependência:

composer require laracasts/presenter

Criando e ligando o Presenter ao Model

A ideia é que cada método trate uma única informação, para mantermos também a classe de presenter organizada. No escopo do presenter é possível acessar as propriedades do model, assim fica mais fácil tratar as informações:

<?php
namespace AppPresenters;

use LaracastsPresenterPresenter;

class ProjectPresenter extends Presenter
{
    public function projectName()
    {
        return $this->id . ' ' . $this->name;
    }

    public function finalDate()
    {
        return $this->final_date->diffForHumans();
    }
}

Estamos criando um método que retorna o nome do projeto com o id e outro que retorna a data final do projeto em um formato mais fácil de ler.

Precisamos indicar o nome do presenter e usar uma trait que possui os métodos do pacote no model. Vamos supor que temos um model chamado Project, ele ficaria assim:

<?php

use AppPresentersProjectPresenter;
use LaracastsPresenterPresentableTrait;
use IlluminateDatabaseEloquentModel;

class Project extends Model
{
    use PresentableTrait;

    protected $presenter = ProjectPresenter::class;
}

Finalmente, agora podemos usar os métodos na view. Basta chamar em uma instancia do model um método chamado present(). Veja o exemplo:

{{ $project->present()->projectName }}

Estamos chamando o método ProjectName do presenter. Assim ele vai imprimir no formato ID Nome do projeto que retornamos no presenter.

Exemplo prático

Vamos imaginar que no model de projetos temos uma propriedade chamada status. Dependendo do status temos que definir a cor do label exibido para o usuário:

  • Status não iniciado: Etiqueta Azul
  • Status no prazo: Etiqueta Verde
  • Status atrasado: Etiqueta Vermelha

Usando as classes do bootstrap poderíamos fazer assim:

<span class="label label-{{ $project->present()->statusLabelColor }}">
    Status aqui
</span>

E no presenter definir a lógica:

<?php
namespace AppPresenters;

use LaracastsPresenterPresenter;

class ProjectPresenter extends Presenter
{
    public function statusLabelColor()
    {
            $labels = [
                'nao-iniciado'  => 'primary',
                'no-prazo'      => 'success',
                'atrasado'      => 'danger'
            ];

            return $labels[$this->status];
    }
}

Isoladamente não parece fazer tanta diferença utilizar os presenters ou não, porém, ao compararmos as views dos projetos que utilizam com os que não utilizam, isso fica muito claro.

O resultado é ainda melhor se o nome dos métodos do presenter forem definidos semanticamente, assim além de remover o código “feio” da view ainda a torna mais fácil de ser lida por humanos.

Laravel - Framework PHP (Parte 2/3)
Curso de Laravel - Framework PHP (Parte 2/3)
CONHEÇA O CURSO
Laravel - Framework PHP (Parte 3/3)
Curso de Laravel - Framework PHP (Parte 3/3)
CONHEÇA O CURSO

Como aliviar seus controllers com os eventos do Eloquent no Laravel

O sonho de todo programador é desenvolver código limpo, organizado, legível, manutenível e muitos outros adjetivos que poderia colocar em uma lista enorme. O Laravel possui vários recursos que nos ajuda a organizar nosso código para conseguir alcançar alguns desses atributos que descrevi acima, se usados de maneira correta. Um desses recursos são os eventos do Eloquent.

Esses eventos são executados sempre que uma ação acontece no model. Isso possibilita removermos responsabilidade dos controllers e executar quando o evento for acionado, com isso, conseguimos um controller mais simples e organizado.

O Eloquent disponibiliza os eventos:

  • Retrieved
  • Creating e Created
  • Updating e Updated
  • Saving e Saved
  • Deleting e Deleted
  • Restoring e Restored

Os eventos com final ing são executados antes da ação no banco de dados e os eventos com final ed são executados após a ação no banco de dados.

Relacionando os eventos no Model

É possível relacionar um evento do Eloquent a um método que fará a ação de três modos diferentes.

Via o método boot

O primeiro modo que podemos adicionar uma ação em um evento do model é através do método estático boot. Por exemplo, para executar uma ação antes da criação podemos fazer:

protected static function boot()
{
    parent::boot();

    static::creating(function ($nomeDoModel) {
        //Ação a ser executada 
    });

}

O Eloquent sempre injeta uma instância do model automaticamente no evento. Nos eventos executados antes da ação no banco é possível alterar os valores do model que serão persistidos.

A utilização dos eventos dentro do próprio model pode não ser a mais aconselhável, pois dependendo da quantidade de eventos pode sobrecarregar, tirando a complexidade dos controllers e transferindo para o models, o que não é bom, pois a solução de um problema criaria outro.

Via classe de evento

Um modo mais limpo de executar os eventos do Eloquent é através de classes específicas para cada um dos eventos. Para isso, basta declarar no model uma propriedade chamada dispatchesEvents com um array contendo o nome do evento e a respectiva classe que será responsável por executar a ação:

protected $dispatchesEvents = [
        'creating' => NomeDoModelCreating::class,
        'deleting' => NomeDoModelDeleting::class,
    ];

Via Observer

Na minha opinião, esse é o modo mais prático de executar ações quando precisamos executar ações em vários eventos do mesmo model.

Essa abordagem consiste basicamente em criar uma classe e declarar métodos públicos com o mesmo nome dos eventos, com isso, o próprio Eloquent verifica se o método existe, se sim, ele executa.

<?php

namespace App\Observers;

use App\NomeDoModel;

class NomeDoModelObserver
{

    public function creating(NomeDoModel $nomeDoModel)
    {
        //Executa antes de criar no banco
    }

    public function deleting(NomeDoModel $nomeDoModel)
    {
        //Executa antes de deletar no banco
    }
}

Único detalhe é que para o Eloquent fazer a referência entre a classe do model e a classe do Observer precisamos declarar dentro do método boot do AppServiceProvider essa relação:

NomeDoModel::observe(NomeDoModelObserver::class);

Note que usamos o método observe() do próprio model que recebe o caminho da classe do observer.

Exemplo prático

Vamos supor que temos uma relação 1 para 1 entre festa e cliente. Baseado nisso, a cada evento do model festa precisamos executar uma ação:

  • Quanto uma festa for criada para um cliente precisamos alterar o status do cliente para com-proposta;
  • Quando uma festa for atualizada, se o atributo valor for maior que zero precisamos alterar o status do cliente para festa-agendada;
  • Por fim, se a festa for excluída, alteramos o status do cliente para sem-proposta;

Nesse caso, podemos criar um observer com os eventos created, updated e deleted para realizar essas ações:

<?php

namespace App\Observers;

use App\Festa;

class FestaObserver
{

    /**
     * Evento executado após a festa ser criada
     *
     * @param Festa $festa
     */
    public function created(Festa $festa)
    {
        $festa->cliente->update(['status' => 'com-proposta']);
    }


    /**
     * Evento executado após a festa ser atualizada
     *
     * @param Festa $festa
     */
    public function updated(Festa $festa)
    {
        if ($festa->valor > 0) {
            $festa->cliente->update(['status' => 'festa-agendada']);
        }
    }

    /**
     * Evento executado após a festa ser deletada
     *
     * @param Festa $festa
     */
    public function deleted(Festa $festa)
    {
        $festa->cliente->update(['status' => 'sem-proposta']);
    }

}

Conclusão

Esse é apenas um dos recursos que podemos usar no Laravel para manter a organização do código. Podemos usar outros como View Composer, Route Model Bind, Policies para permissões, Presenters para remover lógica das views e muito mais.

Quais dos recursos você tem utilizado em seus projetos para melhorar a qualidade do seu código? Fique à vontade para nos contar aqui nos comentários.

Ah, temos um curso muito bom de Laravel no TreinaWeb. Dê uma espiadinha? 🙂

Até a próxima! 🙂