joblo / pdffactory
基于 TCPDF 和 FPDI 的 Yii 扩展,用于创建 PDF 文档
Requires
- php: >=5.3.0
- tecnick.com/tcpdf: dev-master
This package is not auto-updated.
Last update: 2024-09-28 14:46:48 UTC
README
此扩展简化了将 TCPDF、FPDI 以及可选的 yii 扩展 pdfable 集成到您的应用中的过程。
与 FPDI 的结合允许从现有的 PDF 文件中读取页面,并将它们用作模板写入(信头纸等)。
该扩展提供了一个 基础文档类 "EPDFFactoryDoc",您可以在其中设计文档,无需考虑所有围绕集成库和实例化类的繁琐工作。支持创建的 PDF 文档的 缓存功能。
##需求
从 github 下载最新版本的 pdfFactory。
##安装
- 将文件解压到 protected/extensions/pdffactory
- 下载 TCPDF 并将库解压到 protected/extensions/pdffactory/vendors/tcpdf。
- 在您的配置文件 config/main.php 中配置应用程序组件 EPdfFactory
如果配置了 tcpdfPath 和 fpdiPath,则可以将供应商库放置在其他路径。
[php]
'import' => array(
...
'ext.pdffactory.*',
'application.pdf.docs.*', //the path where you place the EPdfFactoryDoc classes
),
'components' => array(
...
'pdfFactory'=>array(
'class'=>'ext.pdffactory.EPdfFactory',
//'tcpdfPath'=>'ext.pdffactory.vendors.tcpdf', //=default: the path to the tcpdf library
//'fpdiPath'=>'ext.pdffactory.vendors.fpdi', //=default: the path to the fpdi library
//the cache duration
'cacheHours'=>5, //-1 = cache disabled, 0 = never expires, hours if >0
//The alias path to the directory, where the pdf files should be created
'pdfPath'=>'application.runtime.pdf',
//The alias path to the *.pdf template files
//'templatesPath'=>'application.pdf.templates', //= default
//the params for the constructor of the TCPDF class
// see: http://www.tcpdf.org/doc/code/classTCPDF.html
'tcpdfOptions'=>array(
/* default values
'format'=>'A4',
'orientation'=>'P', //=Portrait or 'L' = landscape
'unit'=>'mm', //measure unit: mm, cm, inch, or point
'unicode'=>true,
'encoding'=>'UTF-8',
'diskcache'=>false,
'pdfa'=>false,
*/
)
),
),
上述 配置的属性 仅是 默认值。在渲染 PDF 之前,您可以为此属性分配其他值。
您可以使用 composer 下载/安装组件,已包含 composer.json 文件。
##使用方法
###TCPDF / FPDI 实例的基本使用
使用原始 tcpdf / fpdi 实例不是此扩展的目的。但如果你需要,你可以像下面这样实例化这些类。
[php]
//create a TCPDF instance with the params from tcpdfOptions from config/main.php
$pdf=Yii::app()->pdfFactory->getTCPDF();
//use this instance like explained in [TCPDF examples](http://www.tcpdf.org/examples.php "")
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Nicola Asuni');
$pdf->addPage();
$pdf->write(0,'Hello world');
...
$pdf->Output();
//create a TCPDF instance with other tcpdfOptions than the configured default.
$pdf=Yii::app()->pdfFactory->getTCPDF(array('format'=>'A5'));
//create a FPDI instance (always brigded mode so FPDI extends TCPDF)
//see [FPDI](http://www.setasign.com/products/fpdi/about/ "")
$pdf=Yii::app()->pdfFactory->getFPDI(); //other options like above
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Nicola Asuni');
//import the template
$pdf->setSourceFile('...path to pdf template file...');
$tplidx = $pdf->importPage(1);
$pdf->addPage();
$pdf->useTemplate($tplidx, 10, 10, 90);
$pdf->write(0,'Hello world');
...
$pdf->Output();
###使用 EPdfFactoryDoc
在配置的导入路径中为您的 pdf docclasses 创建预定义类,然后在控制器操作中使用几行代码输出 PDF。
您必须重写父类中的以下最小方法
- getPdfName()
- initDocInfo()
- renderPdf()
renderPdf() 必须始终以 $this->addPage() 和 $this->getPdf() 这两行开始;
[php]
class ProductPdf extends EPdfFactoryDoc
{
public function renderPdf()
{
$this->addPage();
$pdf = $this->getPdf();
...
}
...
}
但 不要在此方法中调用 output()。
EPdfFactoryDoc 支持以下方法:setData(), getData() 和 getDataItem()。数据是在 PDF 输出之前分配的简单数组。您可以在文档类内部访问数据。
getPdf() 方法返回 TCPDF 或 FPDI 实例。实例的类型取决于您在输出前是否分配了 PDF 模板。
[php]
class ProductPdf extends EPdfFactoryDoc
{
// the pdf name on creating the (cached) file or downloading.
//always add the extension '.pdf'
public function getPdfName()
{
return $this->getDataItem('model')->title) . '.pdf';
}
// the info assigned to the pdf document
protected function initDocInfo()
{
$pdf = $this->getPdf();
$pdf->SetTitle('My company');
$pdf->SetSubject('Product description');
$pdf->SetKeywords('x, y, z');
}
public function renderPdf()
{
$this->addPage();
$pdf = $this->getPdf();
$pdf->SetFontSize(18);
$model = $this->getDataItem('model');
$pdf->Write(0, 'Article No. ' . $model->id);
//all code to render the pdf, but no output()
...
}
可重写更多方法 - 请查看 EPdfFactoryDoc 的源代码
- initMargins()
- initFont()
- initHeader()
- initFooter()
控制器操作:如果存在 GET 参数 'pdf',则渲染 PDF。
[php]
public function actionProduct($id)
{
$model = Product::model()->findByPk($id); //load from db
if(isset($_GET['pdf']))
{
$productPdf = ProductPdf::doc();
$productPdf->setData(array('model'=>$model));
$productPdf->output(); //destination param = 'I' = standard output to the browser
//other destination params: 'F'=file, 'D'=download, 'S'=string ... see TCPDF docs
//$productPdf->output('D'); //enforce download
}
else
$this->render('product',array('model'=>$model));
}
如果您想将PDF文件指定为模板,您可以通过重写EPdfFactoryDoc类的init()方法,或者在创建文档后使用setTemplate()方法。
如果在创建文档时/之后指定了模板,渲染时内部创建的类将是FPDI而不是TCPDF。因此,您无需考虑FPDI或TCPDF。
[php]
class ProductPdf extends EPdfFactoryDoc
{
public function init()
{
$this->setTemplate('productsheet.pdf', 0, 0, 210); //with defining the area to print in
//override the configured default
//$this->setTcpdfOptions(array('orientation'=>'L', ...);
}
...
}
或者通过在控制器操作中指定模板来提高灵活性。
[php]
public function actionProduct($id)
{
$model = Product::model()->findByPk($id); //load from db
if(isset($_GET['pdf']))
{
$productPdf = ProductPdf::doc();
$productPdf->setTemplate('productsheet1.pdf', 0, 0, 210); //maybe change by action params ...
//$productPdf->setTcpdfOptions(array('orientation'=>'L', ...);
...
}
##更多示例
如果您想通过邮件发送生成的PDF
[php]
public function actionMailProduct($id)
{
$model = Product::model()->findByPk($id); //load from db
$productPdf = ProductPdf::doc();
$productPdf->setData(array('model'=>$model));
$pdfFile=$productPdf->output('F'); //file saved as configured pdfPath/pdfName
... code to attach the file to your mailer and send mail
}
多页PDF
如果您想将不同的产品渲染到同一PDF中
[php]
class ProductPdf extends EPdfFactoryDoc
{
//render a single page for each model
protected function renderPage($model)
{
$this->addPage();
$pdf = $this->getPdf();
...
$pdf->Write(0, 'Article No. ' . $model->id);
...
}
public function renderPdf()
{
foreach($this->getDataItem('models') as $model)
$this->renderPage($model);
}
...
}
[php]
public function actionDownloadProducts()
{
$models = Product::model()->findAll(); //findByAttributes ...
$productPdf = ProductPdf::doc();
$productPdf->setData(array('models'=>$models));
$productPdf->output('D');
}
##缓存
如果您已通过配置'cacheHours' >= 0启用了缓存,则在渲染后将创建PDF文件:路径/名称,其中配置的pdfPath为路径,getPdfName()的结果为名称。
因此,如果您调用$productPdf->output('D'),如果文件不存在或已过期,将创建缓存文件。在下次调用时,将不会再次渲染PDF,而是使用缓存文件发送到浏览器。对于所有其他目的地:F,I,...也是一样。
清除缓存
如果用于生成PDF的数据已更改,请使用方法flushCache()。例如,在模型的afterSave()方法中。或者将其添加到控制器操作actionFlushPdfCache()中。
[php]
Yii::app()->pdfFactory->flushCache(); //all files
Yii::app()->pdfFactory->flushCache('invoice.pdf'); //a single file within the configured pdfPath = cachePath
更多缓存方法
- isCached('invoice.pdf')检查文件是否已缓存
- isCacheEnabled()检查缓存是否启用
- disableCache()暂时禁用缓存
##扩展pdfable
如果您已安装扩展pdfable,您可以在pdfFactory应用程序组件内部配置和使用此扩展。区别在于,您不需要将pdfable操作添加到控制器中,pdfFactory会自动完成。您可以在喜欢的任何控制器中渲染视图/URL。
通过添加额外的键:'pdfableExt','htmlToPdfOptions'和'htmlToPdfPageOptions'将扩展添加到pdfFactory。有关可用选项,请参阅pdfable的文档。
[php]
'components' => array(
...
'pdfFactory'=>array(
'class'=>'ext.pdffactory.EPdfFactory',
...
'pdfableExt'=>'ext.pdfable',
//the pdfable attributes
'htmlToPdfOptions' => array(
//'bin' => '/usr/bin/wkhtmltopdf',
// 'dpi' => 600,
);
//the pdfable page attributes
'$htmlToPdfPageOptions' => array(
// 'page-size' => 'A5',
// 'user-style-sheet' => Yii::getPathOfAlias('webroot').'/css/pdf.css',
);
),
现在您有**renderUrl()和renderView()**方法可用。调用这些方法时,不支持缓存。
通过调用$wkPdf = Yii::app()->pdfFactory->getWkHtmlToPdf();与WkHtmlToPdf实例一起工作。
在控制器中的使用
[php]
public function actionProduct($id)
{
$model = Product::model()->findByPk($id); //load from db
if(isset($_GET['pdf']))
{
Yii::app()->pdfFactory->renderUrl(null,array('id'=>$id)); //the current request url
}
else
$this->render('product',array('model'=>$model));
}
或另一个操作方法(可能在另一个控制器中)
[php]
public function actionRenderProduktPdf(id)
{
Yii::app()->pdfFactory->renderUrl('products/product',array('id'=>$id));
//Yii::app()->pdfFactory->renderUrl('https://yiiframework.cn/');
...
OR
$model = Product::model()->findByPk($id); //load from db
Yii::app()->pdfFactory->renderView('product',array('model'=>$model));
}
##资源
##变更日志
- 1.0.1错误修复:使用多个文档类输出时的问题;多页FPDI模板
- 1.0.0初始发布