Como gerar e inserir gráficos em um arquivo PDF usando Laravel, DOMPDF e Chartjs

Facebook
Twitter
LinkedIn

Olá, amigos! Nesse artigo estarei ensinando de forma fácil a como inserir um gráfico em um arquivo PDF utilizando a biblioteca Chart.js.

Recentemente precisei criar uma aplicação onde ela deveria gerar um gráfico em um arquivo PDF e em seguida enviá-lo por e-mail como anexo. O problema havia começado ai, pois eu estava utilizando uma API em JavaScript para realizar a geração do gráfico e a biblioteca DOMPDF aceitava somente HTML e CSS. A primeira opção que havia pensado na hora foi em buscar uma biblioteca para geração de PDF que aceitasse JavaScript, porém aparentemente não existe nenhuma biblioteca que trabalhe com JavaScript.

Então, em um grupo sobre desenvolvimento web no Telegram acabei encontrando uma biblioteca chamada Quickchart.io que transforma gráficos da Chart.js e imagens, podendo assim ser inserida no blade do PDF. Então, vamos começar!

Tópicos do artigo

  • Criando ambiente
  • Configuração e Instalação do DOMPDF
  • Gerando PDF
  • Enviando PDF por e-mail

Bibliotecas utilizadas

Criando ambiente

Irei começar criando um controller chamado UserController, dois arquivos de visão em nossa pasta views sendo um contendo um formulário solicitando nome e e-mail e o outro sendo apenas o do nosso arquivo PDF que irá conter o nosso gráfico e duas rotas, uma no método GET para abrir o formulário e outra no método POST que será a qual irá disparar a ação que irá montar o PDF com nosso gráfico.

UserController

Para gerar o controller é só rodar o comando:

php artisan make:controller UserController

Dentro dele iremos criar apenas dois métodos:

  • index: que irá nos retornar nossa a view do nosso formulário.
  • getPdf: que irá receber nossos dados via Request e irá nos retornar nosso PDF.

public function index(){
    return view('index');
}

public function getPdf(Request $request){
    //
}

Não vamos mexer no nosso método getPdf até então. Em nossa pasta resouce/views já realizei também a criação de nossos arquivos blade.

  • index.blade.php: possui apenas um formulário contento o action para a rota user.pdf.
  • pdf.blade.php: esse arquivo será o qual irá gerar o nosso PDF, esta em branco.

Nossas rotas

Route::get('/', 'UserController@index')->name('user.index');
Route::post('pdf', 'UserController@pdf')->name('user.pdf');

Configuração e Instalação do DOMPDF

Em seguida, vamos realizar a instalação do DOMPDF para gerar arquivos PDF a partir de uma view blade.

Instalação

O primeiro passo é fazer a instalação da biblioteca através do composer com o seguinte comando no terminal na raiz do nosso projeto:

composer require barryvdh/laravel-dompdf

Configuração

Após a instalação da biblioteca, precisamos registrá-la dentro dos providers da nossa aplicação. Para isso, basta abrir o arquivo app.php localizado em config/app.php. e dentro do providers adicionar na ultima linha o seguinte trecho de código.

Barryvdh\DomPDF\ServiceProvider::class,

Não esqueça de deixar a virgula no final da linha para evitar erros futuros.

Um pouco mais abaixo, precisamos registrar a Facades do DOMPDF em nossos aliases, então assim como fizemos o registro do nosso providers, iremos também registrar na ultima linha dentro do nosso array de aliases. Atenção na virgula no final!

'PDF' => Barryvdh\DomPDF\Facade::class,

Agora devemos executar um comando publish no artisan para ele “publicar” as nossas alterações feitas no config de nossa aplicação com o seguinte comando.

php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"

Caso não apareça nenhum erro no console significa que já podemos começar a utilizar todo o poder que essa biblioteca pode nos apresentar.

Pra não esquecer, vamos em nosso UserController e vamos dar o use em nosso DOMPDF.

use Barryvdh\DomPDF\Facade as PDF;

Gerando PDF

Com o DOMPDF já instalado e configurado da forma certa, agora iremos voltar ao nosso método getPdf no nosso controller UserController e iremos começar a trabalhar também com o o ChartJS e o Quickchart.io.

Entendendo o ChartJS

Não iremos precisar fazer a instalação do ChartJs em nossa aplicação, pois para esse exemplo apenas iremos verificar qual é o gráfico que iremos utilizar para o nosso projeto.

Após escolher o gráfico que atende a sua necessidade, na própria documentação do gráfico escolhido ele já mostra o código dele em Javascript. A estrutura é a mesma que iremos utilizar, mas ele precisará ser transcrevido para o código em PHP. Não é nada complexo e nem requerer algo mirabolante, iremos precisar passar o código de um objeto em JS para um array multidimensional em PHP. Para isso, basta trocar os as chaves por colchetes. Ficando assim:

$chartData = [
  "type" => 'horizontalBar',
    "data" => [
      "labels" => ['Coluna 1', 'Coluna 2', 'Coluna 3'],
        "datasets" => [
          [
            "label" => "Dados", 
            "data" => [100, 60, 20],
            "backgroundColor" => ['#27ae60', '#f1c40f', '#e74c3c']
          ], 
        ],
      ]
  ]; 

Agora, iremos precisar transformar esse código em JSON (o que parece uma piada, mas não é não).

$chartData = json_encode($chartData);

Em seguida iremos enviá-lo via a API do Quickchart.io .

$chartURL = "https://quickchart.io/chart?width=300&height=200&c=".urlencode($chartData);

A função urlencode retorna uma string em que todos os caracteres não-alfanuméricos com exceção de -_. são substituídos com um sinal de por cento (%) seguido por dois dígitos hexadecimais e espaços codificados como um sinal de (+). É codificada do mesmo jeito que dados vindos de um formulário WWW é codificado, isto é, da mesma maneira que application/x-www-form-urlencoded.

A API do Quickchart.io fornece alguns parâmetros a serem passados via URL, como podemos ver nesse exemplo podemos passar o width e o height do gráfico. Além desses dois parâmetros há outras possibilidades, acesse a documentação completa do Quickchart.io para aprender mais algumas se necessário!

Pois bem, agora já temos em nossa variável $chartURL a URL da imagem contendo o gráfico que precisamos. Agora antes de mandá-la para a blade do nosso PDF é importante transformá-la em base64 só para evitar problemas futuros. É bem simples:

$chartData = file_get_contents($chartURL); 
$chart = 'data:image/png;base64, '.base64_encode($chartData);

Agora com tudo pronto, basta enviar a variavel $chart para o blade e o seu gráfico já estara pronto para o uso.

$pdf = PDF::loadView('pdf', compact('chart'))->setPaper('a4')->stream('grafico.pdf');
return $pdf;

No arquivo pdf.blade.php basta apenas chamar a a variavel $chat na tag img para funcionar.

<img src="{{$chart}}">

Enviando PDF por e-mail

Para enviar o gráfico por e-mail é Quickchart.io. Primeiro lembre-se de configurar corretamente o seu .env.

MAIL_DRIVER=smtp
MAIL_HOST=
MAIL_PORT=
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_FROM_ADDRESS=a
MAIL_FROM_NAME=
MAIL_ENCRYPTION=null

E em seguida, precisamos criar a classe que será responsável por enviar o e-mail com o PDF gerado.

php artisan make:mail SendChartForUser

Após rodar o comando será criado (se não existir) um diretório chamado mail dentro de app e dentro dele irá ser criado um arquivo com o nome da classe, no nosso caso será SendChartForUser.

Dentro da nossa nova classe, iremos fazer a seguinte configuração: iremos esperar a passagem de três parâmetros no construtor da nossa classe sendo ele o nome e o email do usuário e o nosso PDF. Em seguida iremos associá-los aos seus respectivos atributos.

    private $name;
    private $email;
    private $pdf;


    public function __construct($name, $email, $pdf)
    {
        $this->name = $name;
        $this->email = $email;
        $this->pdf = $pdf;
    }

    public function build()
    {
        $this->subject('SEU GRAFICO ESTA PRONTO');
        $this->to($this->email, $this->name);
        return $this->view('mail.mail')->attachData($this->pdf, 'grafico.pdf', [
            'mime' => 'application/pdf',
        ]);
    }

No método build iremos definir o assunto do email (subject), para quem ele irá (to) e iremos retornar a view que irá conter o e-mail escrito. A view() iremos atrelar o attachData passando o PDF que iremos receber, que por vez será o PDF que acabamos de gerar.

Voltando ao nosso UserController, em vez de darmos o return $pdf iremos fazer:

Primeiro iremos utilizar o use em nosso Facades Mail e em nossa classe.

use Illuminate\Support\Facades\Mail;
use App\Mail\SendChartForUser;

E em seguida vamos chamar a instancia da nossa classe SendChartForUser passando por parâmetro o nome, o email e o PDF. Esses são os parâmetros que definidos na criação da classe.

Mail::send(new SendChartForUser($request->name, $request->email, $pdf));

Pois bem, agora enviando o formulário com o nosso nome e e-mail, podemos perceber que em seguida em nossa caixa de entrada irá chegar um e-mail com o titulo que definimos e em anexo estará o PDF corretamente.

Mais para explorar

Comentários