Examples

Exemplos PHP

Exemplos completos de integração com PHP, Laravel, Symfony e mais

Exemplos PHP

Exemplos práticos e completos de como integrar o RenderHub em aplicações PHP.

Instalação

composer require guzzlehttp/guzzle vlucas/phpdotenv

Configuração Básica

Variáveis de Ambiente

Crie um arquivo .env:

RENDERHUB_API_KEY=rh_live_sua_chave_aqui
RENDERHUB_BASE_URL=https://renderhub.com/api/v1

Cliente RenderHub

<?php
// lib/RenderHubClient.php

require_once __DIR__ . '/../vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Dotenv\Dotenv;

class RenderHubClient
{
    private $client;
    private $apiKey;
    private $baseUrl;

    public function __construct($apiKey = null)
    {
        // Carregar .env
        $dotenv = Dotenv::createImmutable(__DIR__ . '/..');
        $dotenv->load();

        $this->apiKey = $apiKey ?? $_ENV['RENDERHUB_API_KEY'];
        $this->baseUrl = $_ENV['RENDERHUB_BASE_URL'] ?? 'https://renderhub.com/api/v1';

        if (!$this->apiKey) {
            throw new Exception('RENDERHUB_API_KEY não configurada');
        }

        $this->client = new Client([
            'base_uri' => $this->baseUrl,
            'headers' => [
                'Authorization' => 'Bearer ' . $this->apiKey,
                'Content-Type' => 'application/json'
            ],
            'timeout' => 30
        ]);
    }

    public function render($options)
    {
        try {
            $response = $this->client->post('/render', [
                'json' => $options
            ]);

            return json_decode($response->getBody(), true);

        } catch (RequestException $e) {
            $this->handleError($e);
        }
    }

    public function createTemplate($template)
    {
        try {
            $response = $this->client->post('/templates', [
                'json' => $template
            ]);

            return json_decode($response->getBody(), true);

        } catch (RequestException $e) {
            $this->handleError($e);
        }
    }

    public function getTemplate($templateId)
    {
        try {
            $response = $this->client->get("/templates/{$templateId}");
            return json_decode($response->getBody(), true);

        } catch (RequestException $e) {
            $this->handleError($e);
        }
    }

    public function savePdf($pdfBase64, $filename)
    {
        $pdfBytes = base64_decode($pdfBase64);
        file_put_contents($filename, $pdfBytes);
    }

    private function handleError($exception)
    {
        if ($exception->hasResponse()) {
            $response = $exception->getResponse();
            $status = $response->getStatusCode();
            $body = json_decode($response->getBody(), true);

            switch ($status) {
                case 401:
                    throw new Exception("Erro de autenticação: " . ($body['message'] ?? 'Chave inválida'));
                case 403:
                    throw new Exception("Quota excedida: " . ($body['message'] ?? ''));
                case 429:
                    $retryAfter = $body['retry_after'] ?? 60;
                    throw new Exception("Rate limit excedido. Tente novamente em {$retryAfter}s");
                default:
                    throw new Exception("Erro {$status}: " . ($body['message'] ?? 'Erro desconhecido'));
            }
        }

        throw $exception;
    }
}

Exemplo 1: Converter HTML para PDF

<?php
// examples/convert_html.php

require_once __DIR__ . '/../lib/RenderHubClient.php';

function convertHtmlToPdf()
{
    $client = new RenderHubClient();

    $html = <<<HTML
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <style>
      body {
        font-family: Arial, sans-serif;
        padding: 40px;
        max-width: 800px;
        margin: 0 auto;
      }
      h1 {
        color: #2563eb;
        border-bottom: 3px solid #2563eb;
        padding-bottom: 10px;
      }
      .highlight {
        background: #fef3c7;
        padding: 20px;
        border-radius: 8px;
        margin: 20px 0;
      }
    </style>
  </head>
  <body>
    <h1>Relatório de Vendas - Janeiro 2024</h1>

    <div class="highlight">
      <h2>Resumo</h2>
      <p>Total de vendas: R$ 150.000,00</p>
      <p>Novos clientes: 42</p>
      <p>Taxa de conversão: 15.8%</p>
    </div>

    <h2>Detalhes</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
  </body>
</html>
HTML;

    $result = $client->render([
        'mode' => 'CONVERT',
        'input_type' => 'html',
        'data' => $html,
        'page_size' => 'A4',
        'orientation' => 'portrait'
    ]);

    // Salvar PDF
    $client->savePdf($result['pdf_base64'], 'relatorio.pdf');

    echo "✅ PDF gerado com sucesso!\n";
    echo "Páginas: {$result['pages']}\n";
    echo "Tamanho: {$result['file_size_kb']} KB\n";
    echo "Duração: {$result['duration_ms']}ms\n";
}

convertHtmlToPdf();

Exemplo 2: Fatura com Template

<?php
// examples/generate_invoice.php

require_once __DIR__ . '/../lib/RenderHubClient.php';

function createInvoiceTemplate()
{
    $client = new RenderHubClient();

    $templateHtml = file_get_contents(__DIR__ . '/../templates/invoice.html');

    $template = $client->createTemplate([
        'name' => 'invoice-template-v1',
        'description' => 'Template de fatura padrão',
        'category' => 'invoice',
        'content' => $templateHtml,
        'variables' => [
            ['name' => 'company_name', 'type' => 'string', 'required' => true],
            ['name' => 'invoice_number', 'type' => 'string', 'required' => true],
            ['name' => 'customer_name', 'type' => 'string', 'required' => true],
            ['name' => 'items', 'type' => 'array', 'required' => true],
            ['name' => 'total', 'type' => 'string', 'required' => true]
        ]
    ]);

    echo "Template criado: {$template['id']}\n";
    return $template['id'];
}

function generateInvoice($customerId, $templateId)
{
    $client = new RenderHubClient();

    // Buscar dados do cliente (simulado)
    $customer = [
        'id' => $customerId,
        'name' => 'João Silva Comércio LTDA',
        'email' => 'joao@example.com',
        'address' => 'Rua das Flores, 123',
        'city' => 'São Paulo',
        'state' => 'SP'
    ];

    $orders = [
        ['product' => 'Notebook Dell', 'quantity' => 2, 'price' => 3500.00],
        ['product' => 'Mouse Logitech', 'quantity' => 5, 'price' => 150.00],
        ['product' => 'Teclado Mecânico', 'quantity' => 3, 'price' => 450.00]
    ];

    // Mapear dados para o template
    $items = array_map(function($order) {
        return [
            'description' => $order['product'],
            'quantity' => $order['quantity'],
            'unit_price' => number_format($order['price'], 2, '.', ''),
            'total' => number_format($order['quantity'] * $order['price'], 2, '.', '')
        ];
    }, $orders);

    $subtotal = array_sum(array_map(fn($o) => $o['quantity'] * $o['price'], $orders));

    $invoiceData = [
        'company_name' => 'Minha Empresa LTDA',
        'company_cnpj' => '12.345.678/0001-99',
        'invoice_number' => '2024-' . str_pad($customerId, 5, '0', STR_PAD_LEFT),
        'invoice_date' => date('d/m/Y'),

        'customer_name' => $customer['name'],
        'customer_email' => $customer['email'],
        'customer_address' => "{$customer['address']}, {$customer['city']} - {$customer['state']}",

        'items' => $items,

        'subtotal' => number_format($subtotal, 2, '.', ''),
        'tax' => number_format($subtotal * 0.15, 2, '.', ''),
        'total' => number_format($subtotal * 1.15, 2, '.', '')
    ];

    // Renderizar PDF
    $result = $client->render([
        'mode' => 'RENDER',
        'template_id' => $templateId,
        'data' => $invoiceData
    ]);

    // Salvar PDF
    $filename = "invoice-{$invoiceData['invoice_number']}.pdf";
    $client->savePdf($result['pdf_base64'], $filename);

    echo "✅ Fatura {$invoiceData['invoice_number']} gerada!\n";
    return $filename;
}

// Executar
$templateId = 'tpl_abc123'; // Ou criar com createInvoiceTemplate()
generateInvoice(1001, $templateId);

Exemplo 3: Integração com Laravel

<?php
// app/Services/RenderHubService.php

namespace App\Services;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

class RenderHubService
{
    private $client;
    private $apiKey;

    public function __construct()
    {
        $this->apiKey = config('services.renderhub.api_key');

        $this->client = new Client([
            'base_uri' => 'https://renderhub.com/api/v1',
            'headers' => [
                'Authorization' => 'Bearer ' . $this->apiKey,
                'Content-Type' => 'application/json'
            ],
            'timeout' => 30
        ]);
    }

    public function render($options)
    {
        try {
            $response = $this->client->post('/render', [
                'json' => $options
            ]);

            return json_decode($response->getBody(), true);

        } catch (RequestException $e) {
            throw new \Exception('Erro ao gerar PDF: ' . $e->getMessage());
        }
    }

    public function savePdf($pdfBase64, $path)
    {
        $pdfBytes = base64_decode($pdfBase64);
        \Storage::put($path, $pdfBytes);
        return \Storage::url($path);
    }
}
<?php
// app/Http/Controllers/PdfController.php

namespace App\Http\Controllers;

use App\Services\RenderHubService;
use Illuminate\Http\Request;

class PdfController extends Controller
{
    protected $renderHub;

    public function __construct(RenderHubService $renderHub)
    {
        $this->renderHub = $renderHub;
    }

    public function generatePdf(Request $request)
    {
        $validated = $request->validate([
            'template_id' => 'required|string',
            'data' => 'required|array'
        ]);

        try {
            $result = $this->renderHub->render([
                'mode' => 'RENDER',
                'template_id' => $validated['template_id'],
                'data' => $validated['data']
            ]);

            return response()->json([
                'success' => true,
                'pdf_base64' => $result['pdf_base64'],
                'pages' => $result['pages'],
                'file_size_kb' => $result['file_size_kb']
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'error' => 'Erro ao gerar PDF',
                'message' => $e->getMessage()
            ], 500);
        }
    }

    public function downloadPdf(Request $request)
    {
        $validated = $request->validate([
            'template_id' => 'required|string',
            'data' => 'required|array'
        ]);

        try {
            $result = $this->renderHub->render([
                'mode' => 'RENDER',
                'template_id' => $validated['template_id'],
                'data' => $validated['data']
            ]);

            $pdfBytes = base64_decode($result['pdf_base64']);

            return response($pdfBytes, 200)
                ->header('Content-Type', 'application/pdf')
                ->header('Content-Disposition', 'attachment; filename="document.pdf"');

        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }
}
<?php
// routes/api.php

use App\Http\Controllers\PdfController;

Route::post('/generate-pdf', [PdfController::class, 'generatePdf']);
Route::post('/download-pdf', [PdfController::class, 'downloadPdf']);
<?php
// config/services.php

return [
    // ...
    'renderhub' => [
        'api_key' => env('RENDERHUB_API_KEY'),
    ],
];

Exemplo 4: Webhooks

<?php
// webhook.php

require_once __DIR__ . '/vendor/autoload.php';

use GuzzleHttp\Client;

$WEBHOOK_SECRET = getenv('WEBHOOK_SECRET');

// Receber POST do webhook
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);

// Validar assinatura HMAC
$signature = $_SERVER['HTTP_X_RENDERHUB_SIGNATURE'] ?? '';
$expectedSignature = hash_hmac('sha256', $payload, $WEBHOOK_SECRET);

if ($signature !== $expectedSignature) {
    http_response_code(401);
    echo json_encode(['error' => 'Invalid signature']);
    exit;
}

// Processar webhook
$jobId = $data['job_id'];
$status = $data['status'];

if ($status === 'DONE') {
    error_log("✅ PDF {$data['id']} pronto!");

    // Baixar PDF da URL temporária
    $client = new Client();
    $response = $client->get($data['pdf_url']);
    $pdfContent = $response->getBody();

    // Salvar em storage
    file_put_contents("pdfs/{$data['id']}.pdf", $pdfContent);

    // Atualizar banco de dados
    // $db->query("UPDATE jobs SET status='COMPLETED', pdf_path=? WHERE job_id=?",
    //     ["pdfs/{$data['id']}.pdf", $jobId]);

    // Notificar usuário
    // notifyUser($jobId);

} elseif ($status === 'FAILED') {
    error_log("❌ Erro ao gerar PDF: {$data['error']}");

    // Atualizar banco de dados
    // $db->query("UPDATE jobs SET status='FAILED', error=? WHERE job_id=?",
    //     [$data['error'], $jobId]);
}

// IMPORTANTE: Retornar 200 OK rapidamente
http_response_code(200);
echo json_encode(['received' => true]);

Exemplo 5: Processamento em Lote

<?php
// examples/batch_processing.php

require_once __DIR__ . '/../lib/RenderHubClient.php';

function generateInvoicesForAllCustomers($customerIds, $templateId)
{
    $client = new RenderHubClient();

    foreach ($customerIds as $customerId) {
        try {
            echo "Processando fatura para cliente {$customerId}...\n";

            // Buscar dados do cliente
            $customerData = fetchCustomerData($customerId);

            // Gerar PDF
            $result = $client->render([
                'mode' => 'RENDER',
                'template_id' => $templateId,
                'data' => $customerData
            ]);

            // Salvar
            $filename = "invoices/invoice-{$customerId}.pdf";
            $client->savePdf($result['pdf_base64'], $filename);

            echo "✅ Fatura gerada: {$filename}\n";

        } catch (Exception $e) {
            echo "❌ Erro para cliente {$customerId}: {$e->getMessage()}\n";
        }

        // Aguardar para não exceder rate limit
        usleep(200000); // 200ms = 5 req/s (bem abaixo do limite)
    }

    echo "\nProcessamento concluído!\n";
}

function fetchCustomerData($customerId)
{
    // Simular busca no banco
    return [
        'customer_name' => "Cliente {$customerId}",
        'invoice_number' => "2024-{$customerId}",
        'total' => '1500.00'
    ];
}

// Executar
$customerIds = [1001, 1002, 1003, 1004, 1005];
generateInvoicesForAllCustomers($customerIds, 'tpl_invoice_v1');

Exemplo 6: Retry com Backoff Exponencial

<?php
// lib/retry.php

function generatePdfWithRetry($renderFn, $maxRetries = 3)
{
    for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
        try {
            return $renderFn();

        } catch (Exception $e) {
            $isLastAttempt = $attempt === $maxRetries - 1;

            // Se rate limited, aguardar
            if (strpos($e->getMessage(), 'Rate limit') !== false) {
                if ($isLastAttempt) {
                    throw $e;
                }

                $delay = min(pow(2, $attempt), 30); // Max 30s
                echo "Rate limited. Aguardando {$delay}s...\n";
                sleep($delay);
                continue;
            }

            // Outros erros, não fazer retry
            throw $e;
        }
    }
}

// Uso
require_once __DIR__ . '/RenderHubClient.php';

$client = new RenderHubClient();

$result = generatePdfWithRetry(function() use ($client) {
    return $client->render([
        'mode' => 'CONVERT',
        'input_type' => 'html',
        'data' => '<h1>Test</h1>'
    ]);
});

Exemplo 7: Job Queue com Laravel

<?php
// app/Jobs/GenerateInvoiceJob.php

namespace App\Jobs;

use App\Services\RenderHubService;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class GenerateInvoiceJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $tries = 3;
    public $backoff = [2, 10, 30];

    protected $customerId;
    protected $templateId;

    public function __construct($customerId, $templateId)
    {
        $this->customerId = $customerId;
        $this->templateId = $templateId;
    }

    public function handle(RenderHubService $renderHub)
    {
        \Log::info("Processando fatura para cliente {$this->customerId}");

        // Buscar dados do cliente
        $customerData = $this->fetchCustomerData($this->customerId);

        // Gerar PDF
        $result = $renderHub->render([
            'mode' => 'RENDER',
            'template_id' => $this->templateId,
            'data' => $customerData
        ]);

        // Salvar em storage
        $filename = "invoices/invoice-{$this->customerId}.pdf";
        $renderHub->savePdf($result['pdf_base64'], $filename);

        \Log::info("Fatura gerada: {$filename}");
    }

    private function fetchCustomerData($customerId)
    {
        // Buscar do banco de dados
        return [
            'customer_name' => "Cliente {$customerId}",
            'invoice_number' => "2024-{$customerId}",
            'total' => '1500.00'
        ];
    }
}
<?php
// Disparar jobs

use App\Jobs\GenerateInvoiceJob;

$customerIds = [1001, 1002, 1003, 1004, 1005];
$templateId = 'tpl_invoice_v1';

foreach ($customerIds as $customerId) {
    GenerateInvoiceJob::dispatch($customerId, $templateId);
}

\Log::info(count($customerIds) . ' jobs adicionados à fila');

Exemplo 8: Wrapper PDO para Múltiplos Clientes

<?php
// examples/multi_customer_invoices.php

require_once __DIR__ . '/../lib/RenderHubClient.php';

// Conexão com banco de dados
$db = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'password');

// Buscar clientes ativos
$stmt = $db->query("SELECT id, name, email FROM customers WHERE active = 1");
$customers = $stmt->fetchAll(PDO::FETCH_ASSOC);

$client = new RenderHubClient();
$templateId = 'tpl_invoice_v1';

foreach ($customers as $customer) {
    // Buscar pedidos do cliente
    $stmt = $db->prepare("
        SELECT p.name, oi.quantity, oi.price
        FROM order_items oi
        JOIN products p ON oi.product_id = p.id
        WHERE oi.customer_id = ?
    ");
    $stmt->execute([$customer['id']]);
    $orders = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if (empty($orders)) {
        continue;
    }

    // Mapear dados
    $invoiceData = [
        'customer_name' => $customer['name'],
        'customer_email' => $customer['email'],
        'invoice_number' => date('Y') . '-' . $customer['id'],
        'items' => array_map(function($order) {
            return [
                'description' => $order['name'],
                'quantity' => $order['quantity'],
                'unit_price' => number_format($order['price'], 2),
                'total' => number_format($order['quantity'] * $order['price'], 2)
            ];
        }, $orders),
        'total' => number_format(
            array_sum(array_map(fn($o) => $o['quantity'] * $o['price'], $orders)),
            2
        )
    ];

    // Gerar PDF
    try {
        $result = $client->render([
            'mode' => 'RENDER',
            'template_id' => $templateId,
            'data' => $invoiceData
        ]);

        $filename = "invoices/{$customer['id']}-{$invoiceData['invoice_number']}.pdf";
        $client->savePdf($result['pdf_base64'], $filename);

        echo "✅ Fatura gerada para {$customer['name']}: {$filename}\n";

    } catch (Exception $e) {
        echo "❌ Erro para {$customer['name']}: {$e->getMessage()}\n";
    }
}

Próximos Passos

On this page