feat: add Go, PHP, and Laravel SDKs
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
- Go SDK: zero deps, functional options pattern, full endpoint coverage - PHP SDK: PHP 8.1+, curl-based, PdfOptions class, PSR-4 autoloading - Laravel package: ServiceProvider, Facade, config publishing - All SDKs document complete PDF options including new v0.4.5 params
This commit is contained in:
parent
1545df9a7b
commit
bc67c52d3a
13 changed files with 1133 additions and 0 deletions
156
sdk/php/README.md
Normal file
156
sdk/php/README.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# DocFast PHP SDK
|
||||
|
||||
Official PHP client for the [DocFast](https://docfast.dev) HTML/Markdown to PDF API.
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 8.1+
|
||||
- ext-curl
|
||||
- ext-json
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
composer require docfast/docfast-php
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```php
|
||||
use DocFast\Client;
|
||||
|
||||
$client = new Client('df_pro_your_api_key');
|
||||
|
||||
// HTML to PDF
|
||||
$pdf = $client->html('<h1>Hello World</h1>');
|
||||
file_put_contents('output.pdf', $pdf);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### HTML to PDF
|
||||
|
||||
```php
|
||||
$pdf = $client->html('<h1>Hello</h1><p>My document</p>');
|
||||
```
|
||||
|
||||
### HTML with CSS
|
||||
|
||||
```php
|
||||
$pdf = $client->html(
|
||||
'<h1>Styled</h1>',
|
||||
'h1 { color: navy; font-family: Georgia; }'
|
||||
);
|
||||
```
|
||||
|
||||
### HTML with PDF Options
|
||||
|
||||
```php
|
||||
use DocFast\PdfOptions;
|
||||
|
||||
$options = new PdfOptions();
|
||||
$options->format = 'Letter';
|
||||
$options->landscape = true;
|
||||
$options->margin = ['top' => '20mm', 'bottom' => '20mm', 'left' => '15mm', 'right' => '15mm'];
|
||||
$options->printBackground = true;
|
||||
|
||||
$pdf = $client->html('<h1>Report</h1>', null, $options);
|
||||
```
|
||||
|
||||
### Markdown to PDF
|
||||
|
||||
```php
|
||||
$pdf = $client->markdown('# Hello World\n\nThis is **bold** text.');
|
||||
```
|
||||
|
||||
### URL to PDF
|
||||
|
||||
```php
|
||||
$pdf = $client->url('https://example.com');
|
||||
```
|
||||
|
||||
### Headers and Footers
|
||||
|
||||
```php
|
||||
$options = new PdfOptions();
|
||||
$options->displayHeaderFooter = true;
|
||||
$options->headerTemplate = '<div style="font-size:10px;text-align:center;width:100%">My Document</div>';
|
||||
$options->footerTemplate = '<div style="font-size:10px;text-align:center;width:100%">Page <span class="pageNumber"></span>/<span class="totalPages"></span></div>';
|
||||
$options->margin = ['top' => '40mm', 'bottom' => '20mm'];
|
||||
|
||||
$pdf = $client->html($html, null, $options);
|
||||
```
|
||||
|
||||
### Custom Page Size
|
||||
|
||||
```php
|
||||
$options = new PdfOptions();
|
||||
$options->width = '8.5in';
|
||||
$options->height = '11in';
|
||||
$options->scale = 0.8;
|
||||
|
||||
$pdf = $client->html($html, null, $options);
|
||||
```
|
||||
|
||||
### Templates
|
||||
|
||||
```php
|
||||
// List templates
|
||||
$templates = $client->templates();
|
||||
|
||||
// Render a template
|
||||
$pdf = $client->renderTemplate('invoice', [
|
||||
'company' => 'Acme Corp',
|
||||
'items' => [['name' => 'Widget', 'price' => 9.99]],
|
||||
]);
|
||||
```
|
||||
|
||||
## PDF Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `format` | string | `"A4"` | Page size: A4, Letter, Legal, A3, A5, Tabloid |
|
||||
| `landscape` | bool | `false` | Landscape orientation |
|
||||
| `margin` | array | `null` | Margins with top/bottom/left/right keys (CSS units) |
|
||||
| `printBackground` | bool | `true` | Print background graphics |
|
||||
| `filename` | string | `null` | Suggested filename |
|
||||
| `headerTemplate` | string | `null` | HTML header template |
|
||||
| `footerTemplate` | string | `null` | HTML footer template |
|
||||
| `displayHeaderFooter` | bool | `false` | Show header/footer |
|
||||
| `scale` | float | `1` | Rendering scale (0.1–2.0) |
|
||||
| `pageRanges` | string | `null` | Pages to print (e.g. "1-3,5") |
|
||||
| `preferCSSPageSize` | bool | `false` | Prefer CSS @page size |
|
||||
| `width` | string | `null` | Custom paper width |
|
||||
| `height` | string | `null` | Custom paper height |
|
||||
|
||||
## Error Handling
|
||||
|
||||
```php
|
||||
use DocFast\DocFastException;
|
||||
|
||||
try {
|
||||
$pdf = $client->html('<h1>Test</h1>');
|
||||
} catch (DocFastException $e) {
|
||||
echo "Error: {$e->getMessage()} (status: {$e->statusCode})\n";
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```php
|
||||
// Custom base URL
|
||||
$client = new Client('key', 'https://staging.docfast.dev');
|
||||
|
||||
// Custom timeout (seconds)
|
||||
$client = new Client('key', 'https://docfast.dev', 120);
|
||||
```
|
||||
|
||||
## Laravel Integration
|
||||
|
||||
See the [DocFast Laravel package](../laravel/) for a dedicated Laravel integration with facades, config, and service provider.
|
||||
|
||||
## Links
|
||||
|
||||
- [Documentation](https://docfast.dev/docs)
|
||||
- [API Reference](https://docfast.dev/openapi.json)
|
||||
- [Get an API Key](https://docfast.dev)
|
||||
24
sdk/php/composer.json
Normal file
24
sdk/php/composer.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "docfast/docfast-php",
|
||||
"description": "Official PHP SDK for the DocFast HTML/Markdown to PDF API",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"homepage": "https://docfast.dev",
|
||||
"keywords": ["pdf", "html-to-pdf", "markdown-to-pdf", "api", "docfast"],
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"ext-json": "*",
|
||||
"ext-curl": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DocFast\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "DocFast",
|
||||
"homepage": "https://docfast.dev"
|
||||
}
|
||||
]
|
||||
}
|
||||
183
sdk/php/src/Client.php
Normal file
183
sdk/php/src/Client.php
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DocFast;
|
||||
|
||||
/**
|
||||
* DocFast API client for HTML/Markdown to PDF conversion.
|
||||
*
|
||||
* @see https://docfast.dev/docs
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
private string $apiKey;
|
||||
private string $baseUrl;
|
||||
private int $timeout;
|
||||
|
||||
public function __construct(string $apiKey, string $baseUrl = 'https://docfast.dev', int $timeout = 60)
|
||||
{
|
||||
if (empty($apiKey)) {
|
||||
throw new \InvalidArgumentException('API key is required');
|
||||
}
|
||||
$this->apiKey = $apiKey;
|
||||
$this->baseUrl = rtrim($baseUrl, '/');
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML to PDF.
|
||||
*
|
||||
* @param string $html HTML content
|
||||
* @param string|null $css Optional CSS to inject
|
||||
* @param PdfOptions|null $options PDF options
|
||||
* @return string Raw PDF bytes
|
||||
* @throws DocFastException
|
||||
*/
|
||||
public function html(string $html, ?string $css = null, ?PdfOptions $options = null): string
|
||||
{
|
||||
$body = ['html' => $html];
|
||||
if ($css !== null) {
|
||||
$body['css'] = $css;
|
||||
}
|
||||
return $this->convert('/v1/convert/html', $body, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Markdown to PDF.
|
||||
*
|
||||
* @param string $markdown Markdown content
|
||||
* @param string|null $css Optional CSS to inject
|
||||
* @param PdfOptions|null $options PDF options
|
||||
* @return string Raw PDF bytes
|
||||
* @throws DocFastException
|
||||
*/
|
||||
public function markdown(string $markdown, ?string $css = null, ?PdfOptions $options = null): string
|
||||
{
|
||||
$body = ['markdown' => $markdown];
|
||||
if ($css !== null) {
|
||||
$body['css'] = $css;
|
||||
}
|
||||
return $this->convert('/v1/convert/markdown', $body, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a URL to PDF.
|
||||
*
|
||||
* @param string $url URL to convert
|
||||
* @param PdfOptions|null $options PDF options
|
||||
* @return string Raw PDF bytes
|
||||
* @throws DocFastException
|
||||
*/
|
||||
public function url(string $url, ?PdfOptions $options = null): string
|
||||
{
|
||||
return $this->convert('/v1/convert/url', ['url' => $url], $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* List available templates.
|
||||
*
|
||||
* @return array<array{id: string, name: string, description?: string}>
|
||||
* @throws DocFastException
|
||||
*/
|
||||
public function templates(): array
|
||||
{
|
||||
$data = $this->get('/v1/templates');
|
||||
$result = json_decode($data, true);
|
||||
return $result['templates'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a template to PDF.
|
||||
*
|
||||
* @param string $templateId Template ID
|
||||
* @param array $data Template data
|
||||
* @return string Raw PDF bytes
|
||||
* @throws DocFastException
|
||||
*/
|
||||
public function renderTemplate(string $templateId, array $data = []): string
|
||||
{
|
||||
return $this->post('/v1/templates/' . urlencode($templateId), ['data' => $data]);
|
||||
}
|
||||
|
||||
private function convert(string $path, array $body, ?PdfOptions $options): string
|
||||
{
|
||||
if ($options !== null) {
|
||||
$body = array_merge($body, $options->toArray());
|
||||
}
|
||||
return $this->post($path, $body);
|
||||
}
|
||||
|
||||
private function post(string $path, array $body): string
|
||||
{
|
||||
$ch = curl_init($this->baseUrl . $path);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($body),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => $this->timeout,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: Bearer ' . $this->apiKey,
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/pdf',
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
throw new DocFastException('Request failed: ' . $error, 0);
|
||||
}
|
||||
|
||||
if ($statusCode >= 400) {
|
||||
$this->handleError($response, $statusCode);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function get(string $path): string
|
||||
{
|
||||
$ch = curl_init($this->baseUrl . $path);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => $this->timeout,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: Bearer ' . $this->apiKey,
|
||||
'Accept: application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
throw new DocFastException('Request failed: ' . $error, 0);
|
||||
}
|
||||
|
||||
if ($statusCode >= 400) {
|
||||
$this->handleError($response, $statusCode);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function handleError(string $response, int $statusCode): never
|
||||
{
|
||||
$message = "HTTP $statusCode";
|
||||
$code = null;
|
||||
|
||||
$data = json_decode($response, true);
|
||||
if (is_array($data)) {
|
||||
$message = $data['error'] ?? $message;
|
||||
$code = $data['code'] ?? null;
|
||||
}
|
||||
|
||||
throw new DocFastException($message, $statusCode, $code);
|
||||
}
|
||||
}
|
||||
18
sdk/php/src/DocFastException.php
Normal file
18
sdk/php/src/DocFastException.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DocFast;
|
||||
|
||||
class DocFastException extends \RuntimeException
|
||||
{
|
||||
public readonly int $statusCode;
|
||||
public readonly ?string $errorCode;
|
||||
|
||||
public function __construct(string $message, int $statusCode, ?string $errorCode = null, ?\Throwable $previous = null)
|
||||
{
|
||||
$this->statusCode = $statusCode;
|
||||
$this->errorCode = $errorCode;
|
||||
parent::__construct($message, $statusCode, $previous);
|
||||
}
|
||||
}
|
||||
65
sdk/php/src/PdfOptions.php
Normal file
65
sdk/php/src/PdfOptions.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DocFast;
|
||||
|
||||
/**
|
||||
* PDF generation options.
|
||||
*/
|
||||
class PdfOptions
|
||||
{
|
||||
/** Page size: A4, Letter, Legal, A3, A5, Tabloid. Ignored if width/height set. */
|
||||
public ?string $format = null;
|
||||
|
||||
/** Landscape orientation. */
|
||||
public ?bool $landscape = null;
|
||||
|
||||
/** Page margins using CSS units (e.g. "20mm"). */
|
||||
public ?array $margin = null;
|
||||
|
||||
/** Print background graphics and colors. */
|
||||
public ?bool $printBackground = null;
|
||||
|
||||
/** Suggested filename for the PDF download. */
|
||||
public ?string $filename = null;
|
||||
|
||||
/** HTML template for page header. Requires displayHeaderFooter: true. */
|
||||
public ?string $headerTemplate = null;
|
||||
|
||||
/** HTML template for page footer. */
|
||||
public ?string $footerTemplate = null;
|
||||
|
||||
/** Show header and footer templates. */
|
||||
public ?bool $displayHeaderFooter = null;
|
||||
|
||||
/** Scale of webpage rendering (0.1 to 2.0). */
|
||||
public ?float $scale = null;
|
||||
|
||||
/** Paper ranges to print, e.g. "1-3,5". */
|
||||
public ?string $pageRanges = null;
|
||||
|
||||
/** Give CSS @page size priority over format. */
|
||||
public ?bool $preferCSSPageSize = null;
|
||||
|
||||
/** Paper width with units (e.g. "8.5in"). Overrides format. */
|
||||
public ?string $width = null;
|
||||
|
||||
/** Paper height with units (e.g. "11in"). Overrides format. */
|
||||
public ?string $height = null;
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$data = [];
|
||||
foreach ([
|
||||
'format', 'landscape', 'margin', 'printBackground', 'filename',
|
||||
'headerTemplate', 'footerTemplate', 'displayHeaderFooter',
|
||||
'scale', 'pageRanges', 'preferCSSPageSize', 'width', 'height',
|
||||
] as $key) {
|
||||
if ($this->$key !== null) {
|
||||
$data[$key] = $this->$key;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue