renatio/dynamicpdf-plugin

October HTML到PDF转换器,使用dompdf库。

安装数: 12,183

依赖: 3

建议: 0

安全: 0

星星: 31

关注者: 4

分支: 22

开放问题: 2

类型:october-plugin

v7.1.2 2023-10-27 10:34 UTC

This package is auto-updated.

Last update: 2024-08-27 12:27:06 UTC


README

演示URL: https://october-demo.renatio.com/backend/backend/auth/signin

登录: dynamicpdf

密码: dynamicpdf

此插件允许开发人员通过简单的用户界面创建和编辑PDF模板。

HTML到PDF转换器使用dompdf库。

插件使用Laravel的dompdf包装barryvdh/laravel-dompdf

喜欢这个插件吗?

如果你喜欢这个插件,请给它点赞或通过PayPal捐款。

我的其他插件

请查看我的其他插件

支持

请使用GitHub问题页面报告插件中的任何问题。

评论不应用于获取支持或报告错误,如需支持,请使用插件支持链接。

图标由Darius Dan来自www.flaticon.com制作。

文档

安装

安装此插件有多种方式。

  1. 使用php artisan plugin:install Renatio.DynamicPDF命令。
  2. 在项目根目录中使用composer require renatio/dynamicpdf-plugin。当你使用此选项时,必须在安装后运行php artisan october:migrate

PDF内容

在October中,可以使用PDF视图或PDF模板创建PDF。PDF视图由插件提供,位于文件系统中的/views目录。而PDF模板则通过后端界面在设置 > PDF > PDF模板中进行管理。所有PDF模板都支持使用Twig进行标记。

PDF视图必须通过插件注册文件中的registerPDFTemplatesregisterPDFLayouts方法进行注册。这将自动生成PDF模板和布局,并允许通过后端界面进行自定义。

PDF布局视图

PDF布局视图位于文件系统中,使用的代码代表视图文件的路径。例如,代码为author.plugin::pdf.layouts.default的PDF布局将使用以下文件中的内容

plugins/                 <=== Plugins directory
  author/                <=== "author" segment
    plugin/              <=== "plugin" segment
      views/             <=== View directory
        pdf/             <=== "pdf" segment
          layouts/       <=== "layouts" segment
            default.htm  <=== "default" segment

PDF视图文件内的内容可以包括最多3个部分: 配置CSS/LESSHTML标记。部分由==序列分隔。例如

name = "Default PDF layout"
==
body {
    font-size: 16px;
}
==
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>Document</title>
        <style type="text/css" media="screen">
            {{ css|raw }}
        </style>
    </head>
    <body>
        {{ content_html|raw }}
    </body>
</html>

注意:PDF视图中支持基本Twig标签和表达式。

CSS/LESS部分是可选的,视图可以只包含配置和HTML标记部分。

name = "Default PDF layout"
==
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>Document</title>
        <style type="text/css" media="screen">
            {{ css|raw }}
        </style>
    </head>
    <body>
        {{ content_html|raw }}
    </body>
</html>

配置部分

配置部分设置PDF视图参数。以下配置参数受支持

使用PDF布局

PDF布局存储在数据库中,可以通过选择设置 > PDF > PDF模板并点击*布局*选项卡来创建。它们的行为就像CMS布局一样,包含PDF的框架。PDF视图和模板支持使用PDF布局。布局中指定的代码是唯一的标识符,一旦创建就不能更改。

PDF模板视图

PDF模板存储在文件系统中,使用的代码表示视图文件的路径。例如,代码为author.plugin::pdf.invoice的PDF模板将使用以下文件的内容:

plugins/                 <=== Plugins directory
  author/                <=== "author" segment
    plugin/              <=== "plugin" segment
      views/             <=== View directory
        pdf/             <=== "pdf" segment
          invoice.htm    <=== "invoice" segment

PDF视图文件内的内容可以包括最多2个部分:配置HTML标记。部分由==序列分隔。例如:

title = "Invoice"
layout = "renatio.demo::pdf.layouts.default"
description = "Invoice template"
size = "a4"
orientation = "portrait"
==
<h1>Invoice</h1>

注意:PDF视图中支持基本Twig标签和表达式。

配置部分

配置部分设置PDF视图参数。以下配置参数受支持

使用PDF模板

PDF模板存储在数据库中,可以通过设置 > PDF > PDF模板在后台区域创建。模板中指定的代码是唯一的标识符,一旦创建就不能更改。

注意:如果系统中不存在PDF模板,此代码将尝试查找具有相同代码的PDF视图。

注册PDF模板和布局

PDF视图可以作为模板注册,这些模板将在后台自动生成,以便进行自定义。可以通过设置 > PDF模板菜单自定义PDF模板。可以通过添加插件注册类(Plugin.php)的registerPDFTemplates方法来注册模板。

public function registerPDFTemplates()
{
    return [
        'renatio.demo::pdf.invoice',
        'renatio.demo::pdf.resume',
    ];
}

该方法应返回一个包含PDF视图名称的数组。

就像模板一样,PDF布局也可以通过添加插件注册类(Plugin.php)的registerPDFLayouts方法来注册。

public function registerPDFLayouts()
{
    return [
        'renatio.demo::pdf.layouts.invoice',
        'renatio.demo::pdf.layouts.resume',
    ];
}

该方法应返回一个包含PDF视图名称的数组。

用法

可以通过设置 > PDF > PDF模板在后台区域访问PDF模板和布局。

布局定义了PDF框架,即PDF上重复出现的一切,例如页眉和页脚。每个布局都有唯一的代码、可选的背景图像、HTML内容和CSS/LESS内容。并非所有CSS属性都受支持,因此请检查CSS兼容性

模板定义了从HTML解析的实际PDF内容。

配置

默认配置设置在config/dompdf.php中。将此文件复制到您的自己的配置目录以修改值。您可以使用以下命令发布配置:

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

您仍然可以在生成PDF之前使用动态方法更改dompdf选项,例如:

PDF::loadTemplate('renatio::invoice')
    ->setDpi(300)
    ->setDefaultFont('sans-serif')
    ->stream();

或者您可以在使用以下命令生成PDF之前使用setOption方法:

PDF::loadTemplate('renatio::invoice')
    ->setOption(['dpi' => 300, 'defaultFont' => 'sans-serif'])
    ->stream();

可用选项及其默认值

  • rootDir: "{app_directory}/vendor/dompdf/dompdf"
  • tempDir: "/tmp" (在config/dompdf.php中可用)
  • fontDir: "{app_directory}/storage/fonts/" (在config/dompdf.php中可用)
  • fontCache: "{app_directory}/storage/fonts/" (在config/dompdf.php中可用)
  • chroot: "{app_directory}" (在config/dompdf.php中可用)
  • logOutputFile: "/tmp/log.htm"
  • defaultMediaType: "screen" (在config/dompdf.php中可用)
  • defaultPaperSize: "a4" (在config/dompdf.php中可用)
  • defaultFont: "serif" (在config/dompdf.php中可用)
  • dpi: 96 (在config/dompdf.php中可用)
  • fontHeightRatio: 1.1 (在config/dompdf.php中可用)
  • isPhpEnabled: false (在config/dompdf.php中可用)
  • isRemoteEnabled: true (在config/dompdf.php中可用)
  • isJavascriptEnabled: true (在config/dompdf.php中可用)
  • isHtml5ParserEnabled: false (在config/dompdf.php中可用)
  • isFontSubsettingEnabled: false (在config/dompdf.php中可用)
  • debugPng: false
  • debugKeepTemp: false
  • debugCss: false
  • debugLayout: false
  • debugLayoutLines: true
  • debugLayoutBlocks: true
  • debugLayoutInline: true
  • debugLayoutPaddingBox: true
  • pdfBackend: "CPDF" (可在 config/dompdf.php 中配置)
  • pdflibLicense: ""
  • adminUsername: "user"
  • adminPassword: "password"

请参考Dompdf\Options以获取可用选项列表。

方法

所有方法都可通过 Facade 类 Renatio\DynamicPDF\Classes\PDF 获取。

提示

背景图片

要显示布局中添加的背景图片,请使用以下代码

<body style="background: url({{ background_img }}) top left no-repeat;">

背景图片至少应为 96 DPI 大小(793 x 1121 px)。

如果您想使用更高分辨率的图片,如 300 DPI(2480 x 3508 px),则需要更改模板选项,如下所示

return PDF::loadTemplate($model->code)
    ->setDpi(300)
    ->stream();

UTF-8 支持

在您的布局中,在 head 部分设置 UTF-8 元标签

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

如果您遇到外文字符问题,请尝试使用 DejaVu Sans 字体族。

分页

您可以使用 CSS 的 page-break-before/page-break-after 属性创建新页面。

<style>
.page-break {
    page-break-after: always;
}
</style>
<h1>Page 1</h1>
<div class="page-break"></div>
<h1>Page 2</h1>

基于目录的开放限制错误

在一些主机提供商上,有关于日志文件中 open_basedir 限制问题的报告。您可以更改默认日志文件目标,如下所示

return PDF::loadTemplate('renatio::invoice')
    ->setLogOutputFile(storage_path('temp/log.htm'))
    ->stream();

在 PDF 模板中嵌入图片

您可以使用绝对路径,例如 https://app.dev/path_to_your_image

为了使此功能正常工作,您必须设置 isRemoteEnabled 选项。

return PDF::loadTemplate('renatio::invoice', ['file' => $file])
    ->setIsRemoteEnabled(true)
    ->stream();

我假设 $fileOctober\Rain\Database\Attach\File 的实例。

然后在模板中,您可以使用以下示例代码

{{ file.getPath }}

{{ file.getLocalPath }}

{{ file.getThumb(200, 200, {'crop' => true}) }}

为了通过 HTTP 获取样式表或图片,必须启用以下 PHP 设置 allow_url_fopen

如果服务器上禁用了 allow_url_fopen,请尝试使用相对路径。您可以使用 October 的 getLocalPath 函数在文件对象上获取它。

通过 Ajax 响应下载 PDF

OctoberCMS Ajax 框架无法处理此类响应。

建议的方法是将 PDF 文件本地保存并返回到 PDF 文件的重定向。

页码

可以使用 PHP 生成页码。默认情况下,内联 PHP 已禁用,因为它可能是一个安全风险。您可以使用 setIsPhpEnabled 方法启用内联 PHP。

return PDF::loadTemplate('renatio::invoice')
    ->setIsRemoteEnabled(true)
    ->setIsPhpEnabled(true)
    ->stream();

之后,您必须在布局文件的 </body> 标签之前放置以下代码。

<script type="text/php">
    if (isset($pdf)) {
        $size = 9;
        $color = [0,0,0];

        $font = $fontMetrics->getFont('Open Sans');
        $textHeight = $fontMetrics->getFontHeight($font, $size);
        $width = $fontMetrics->getTextWidth('Page 1 of 2', $font, $size);

        $foot = $pdf->open_object();

        $w = $pdf->get_width();
        $h = $pdf->get_height();

        $y = $h - $textHeight - 13;

        $pdf->close_object();
        $pdf->add_object($foot, 'all');

        $text = "Page {PAGE_NUM} of {PAGE_COUNT}";

        // Center the text
        $pdf->page_text($w / 2 - $width / 2, $y, $text, $font, $size, $color);
    }
</script>

示例

演示示例

有一个控制台命令可以启用演示模板和布局。

php artisan dynamicpdf:demo

要禁用演示,请运行以下命令

php artisan dynamicpdf:demo --disable

第一个示例显示了带有自定义字体和图片嵌入的发票。

第二个示例显示了使用页眉和页脚、分页、页码和全背景图片的用法。

在浏览器中渲染 PDF

use Renatio\DynamicPDF\Classes\PDF; // import facade

public function pdf()
{
    $templateCode = 'renatio::invoice'; // unique code of the template
    $data = ['name' => 'John Doe']; // optional data used in template

    return PDF::loadTemplate($templateCode, $data)->stream('download.pdf');
}

其中 $templateCode 是创建模板时指定的唯一代码,$data 是可选的 twig 字段数组,它将在模板中替换。

在 HTML 模板中,您可以使用 {{ name }} 输出 John Doe

下载 PDF

use Renatio\DynamicPDF\Classes\PDF;

public function pdf()
{
    return PDF::loadTemplate('renatio::invoice')->download('download.pdf');
}

流畅接口

您可以链式调用方法

return PDF::loadTemplate('renatio::invoice')
    ->save('/path-to/my_stored_file.pdf')
    ->stream();

更改纸张大小和方向

return PDF::loadTemplate('renatio::invoice')
    ->setPaper('a4', 'landscape')
    ->stream();

支持的 纸张大小

在 CMS 页面上显示 PDF

要显示 CMS 页面上的 PDF,您可以使用页面上的 PHP 部分,如下所示

use Renatio\DynamicPDF\Classes\PDF;

function onStart()
{
    return PDF::loadTemplate('renatio::invoice')->stream();
}

每页的页眉和页脚

<html>
<head>
  <style>
    @page { margin: 100px 25px; }
    header { position: fixed; top: -60px; left: 0px; right: 0px; background-color: lightblue; height: 50px; }
    footer { position: fixed; bottom: -60px; left: 0px; right: 0px; background-color: lightblue; height: 50px; }
    p { page-break-after: always; }
    p:last-child { page-break-after: never; }
  </style>
</head>
<body>
  <header>header on each page</header>
  <footer>footer on each page</footer>
  <main>
    <p>page1</p>
    <p>page2</p>
  </main>
</body>
</html>

使用自定义字体

插件提供 "Open Sans" 字体,您可以在布局 CSS 部分导入。

@font-face {
    font-family: 'Open Sans';
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Regular.ttf'|app }});
}

@font-face {
    font-family: 'Open Sans';
    font-weight: bold;
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Bold.ttf'|app }});
}

@font-face {
    font-family: 'Open Sans';
    font-style: italic;
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Italic.ttf'|app }});
}

@font-face {
    font-family: 'Open Sans';
    font-style: italic;
    font-weight: bold;
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-BoldItalic.ttf'|app }});
}

body {
    font-family: 'Open Sans', sans-serif;
    font-size: 16px;
}