joblo/pdffactory

基于 TCPDF 和 FPDI 的 Yii 扩展,用于创建 PDF 文档

安装: 51

依赖: 0

建议: 0

安全: 0

星星: 2

观察者: 3

分支: 0

开放问题: 1

类型:yii-extension

dev-master 2015-03-09 07:40 UTC

This package is not auto-updated.

Last update: 2024-09-28 14:46:48 UTC


README

此扩展简化了将 TCPDFFPDI 以及可选的 yii 扩展 pdfable 集成到您的应用中的过程。

与 FPDI 的结合允许从现有的 PDF 文件中读取页面,并将它们用作模板写入(信头纸等)。

该扩展提供了一个 基础文档类 "EPDFFactoryDoc",您可以在其中设计文档,无需考虑所有围绕集成库和实例化类的繁琐工作。支持创建的 PDF 文档的 缓存功能

##需求

  • PHP 5.3+
  • 使用 Yii 1.1.14 开发(未测试旧版本,但应该也能工作)
  • TCPDF 不包含。
  • 可选:pdfable 不包含。
  • 包含:FPDI

github 下载最新版本的 pdfFactory。

##安装

  1. 将文件解压到 protected/extensions/pdffactory
  2. 下载 TCPDF 并将库解压到 protected/extensions/pdffactory/vendors/tcpdf。
  3. 在您的配置文件 config/main.php 中配置应用程序组件 EPdfFactory

如果配置了 tcpdfPathfpdiPath,则可以将供应商库放置在其他路径。

[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初始发布