2lenet / pdf-generator-bundle
PDF生成器
Requires
- php: ^8.0
- alexanderpavlov/pdfmerger: ^1.0
- doctrine/annotations: ^1.13
- doctrine/orm: ^2.6 || ^3.0
- laminas/laminas-escaper: ^2.11
- laminas/laminas-stdlib: ^3.15
- phpoffice/phpword: ^0.18
- setasign/fpdf: 1.8.4
- setasign/fpdi: ^2.3.6
- symfony/dotenv: ^6.0 || ^7.0
- symfony/framework-bundle: ^6.0 || ^7.0
- symfony/http-client-contracts: ^v3.4.0
- symfony/http-foundation: ^6.0 || ^7.0
- symfony/process: ^6.0 || ^7.0
- symfony/property-access: ^6.0 || ^7.0
- symfony/routing: ^6.0 || ^7.0
- symfony/serializer: ^6.0 || ^7.0
- symfony/yaml: ^6.0 || ^7.0
- tecnickcom/tcpdf: ^6.3
- twig/twig: ^3.4.3
- vich/uploader-bundle: ^1.19 || ^2.0
Requires (Dev)
- ergebnis/phpstan-rules: ^2.1
- phpstan/phpstan: ^1.10
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-doctrine: ^1.3
- phpstan/phpstan-mockery: ^1.1
- phpstan/phpstan-phpunit: ^1.3
- phpstan/phpstan-strict-rules: ^1.5
- phpstan/phpstan-symfony: ^1.3
- phpunit/phpunit: ^10.3
- slevomat/coding-standard: ^8.13
- squizlabs/php_codesniffer: ^3.7
- dev-master
- 4.1.0
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- 3.0.1
- 3.0.0
- 2.0.0
- 1.7.7
- 1.7.6
- 1.7.5
- 1.7.4
- 1.7.3
- 1.7.1
- 1.7.0
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.3
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.0
- 1.2.3
- 1.2.2
- 1.2
- 1.1
- 1.0.2
- v1.0.1
- 1.0.0
- dev-sf-7
- dev-saut-de-ligne
- dev-fix_default_null_properties-1
- dev-fixDeprecated
- dev-fixSymfonyInsightErrors
- dev-iBast-patch-1
- dev-editController
- dev-compatibilitySf6
- dev-fixFPDFversion
- dev-sf6Compatibility-1
- dev-sf6Compatibility
- dev-bugfix/avoid-duplicate-code
- dev-zend
- dev-compatible-php8
- dev-compatible
- dev-feature/allow-images-in-iterables
- dev-routeBalise
- dev-correctionBalise
- dev-balises
- dev-model_exception
- dev-signature_colour
- dev-complex_block
- dev-variablesAutomatiques
- dev-specialchar_template
This package is auto-updated.
Last update: 2024-09-07 12:51:07 UTC
README
安装
composer require 2lenet/pdf-generator-bundle
需求:unoserver(用于word_to_pdf)
unoserver:
image: registry.2le.net/2le/2le:unoserver
配置
config(默认值)
lle_pdf_generator: path: "data/pdfmodel" default_generator: "word_to_pdf" class: 'Lle\PdfGeneratorBundle\Entity\PdfModel'
添加路由(通过<a href="{{ path('lle_pdf_generator_show_ressource', {'id': item.id}) }}">
显示资源)
lle_pdf_generator: resource: "@LlePdfGeneratorBundle/Resources/config/routes.yaml" prefix: /
如果您创建了一个没有类型且资源为mydoc.doc的模型,生成器将基于data/pdfmodel/mydoc.doc使用word_to_pdf生成器创建PDF。
配置您的标签
您可以轻松列出模型中使用的标签。
为此,只需声明将列出标签的页面的路由。路由名为" lle_pdf_generator_admin_balise"。
在Crudit中的示例
public function getListActions(): array { $actions = parent::getListActions(); array_unshift($actions, ListAction::new( "action.balise", Path::new('lle_pdf_generator_admin_balise'), Icon::new("bookmark") )); return $actions; }
如果您使用多个与不同模块链接的文档模板,您可以在项目的pdf_generator.yaml中声明您的注解
lle_pdf_generator: path: "data/pdfmodel" default_generator: "word_to_pdf" data_models: - facture - commande
为了完成标签列表,使用在pdf_generator.yaml文件中声明的Symfony注解。例如
<?php namespace App\Entity use Symfony\Component\Serializer\Annotation\Groups; class Commande { /** * @Groups({"commande"}) */ private $type; }
如果您只有一个模板或一个模块使用多个模板,您不必在pdf_generator.yaml文件中声明"data_models"。默认情况下,Symfony注解将是"pdfgenerator"。然后,在您的实体中,您将拥有
<?php namespace App\Entity use Symfony\Component\Serializer\Annotation\Groups; class Commande { /** * @Groups({"pdfgenerator"}) */ private $type; }
使用方法
您可以使用PDF生成器与数据库或直接在代码中使用
<?php /** * @Route("/pdf") */ public function pdf(PdfGenerator $generator, UserRepository $userRepository) { $data = []; foreach($userRepository->findAll() as $user){ $data[] = ['name' => $user->getName()]; } //create an response by Bdd return $generator->generateResponse('MYMODELCODE', $data); //or //create an PdfMerger by Bdd $generator->generate('MYMODELCODE', $data)->merge('pdf.pdf','F'); //or //create an PdfMerger by ressource return $generator->generateByRessourceResponse(TcpdfGenerator::getName(), MyTcpdfClass::class, $data); //or //create an response by ressource $generator->generateByRessource(TcpdfGenerator::getName(), MyTcpdfClass::class, $data)->merge('pdf.pdf','F'); }
您可以使用PdfMerger创建TcpdfFpdi(Tcpdf和Fpdi)的实例
<?php $pdfMerger = $generator->generate('MYMODELCODE', $data)->merge('pdf.pdf','F'); $pdf = $pdfMerger->toTcpdfFpdi(); $pdf->addPage('P'); $pdf->writeHTML('Hello', true, 0, true, 0); $pdf->Output('file.pdf', 'F'); return new ResponseBinaryFile('file.pdf');
与实体一起使用
更改PDF生成器配置中的"类"为"App/Entity/MyModelPdf"
<?php namespace App\Entity; use Vich\UploaderBundle\Mapping\Annotation as Vich; use Doctrine\ORM\Mapping as ORM; use Lle\PdfGeneratorBundle\Entity as PDF; /** * * @ORM\Table(name="lle_pdf_model", indexes={@ORM\Index(name="code_idx", columns={"code"})}) * @ORM\Entity * @Vich\Uploadable */ class MyModelPdf implements PDF\PdfModelInterface { use PDF\PdfModelTrait; }
与数据库一起使用
模型是具有以下内容的PdfModel:
代码、资源、名称、类型和描述
您可以使用以下方式创建模型:
php bin/console lle:pdf-generator:create-model
!!警告:如果您使用自己的类并且该类有其他带有约束的字段,则命令将无法工作。!!
创建自己的类型
您可以创建多种PDF类型(已存在tcpdf和word_to_pdf)
- word_to_pdf(资源是.docx格式Microsoft Word XML的路径)
- tcpdf(资源是扩展Lle\PdfGeneratorBundle\Lib\Pdf(Tcpdf和Fpdi)的类)
您可以通过扩展Lle\PdfGeneratorBundle\Generator\AbstractPdfGenerator的类创建自己的类型
AbstractPdfGenerator实现了Lle\PdfGeneratorBundle\Generator\PdfGeneratorInterface(自动标记为lle.pdf.generator)
public static function getName():string; //name of type public function generate(string $source, iterable $params, string $savePath):void; //generate the pdf with the ressource $source and parameters $params in a tmp file $savePath public function getRessource(string $pdfPath, string $modelRessource): string; //calcule the ressource with pdfPath or not (the ressource can be an class name for exemple)
示例
<?php class TcpdfGenerator extends AbstractPdfGenerator { private $pdfPath; public function generate(string $source, iterable $params, string $savePath):void{ $reflex = new \ReflectionClass($source); $pdf = $reflex->newInstance(); if ($pdf instanceof Pdf) { $pdf->setRootPath($this->pdfPath); $pdf->setData($params['vars']); $pdf->initiate(); $pdf->generate(); $pdf->setTitle($pdf->title()); } else { throw new \Exception('PDF GENERATOR ERROR: ressource '.$source.' n\'est pas une class PDF'); } $pdf->output($savePath, 'F'); } //$pdfPath is in config lle_pdf_generator.path (default:data/pdfmodel) public function getRessource(string $pdfPath, string $modelRessource): string{ $this->pdfPath = $pdfPath; return $modelRessource; } public static function getName(): string{ return 'tcpdf'; } }
使用tcpdf类型
tcpdf的示例
<?php namespace App\Service\Pdf; use Lle\PdfGeneratorBundle\Lib\Pdf; class MyTcpdfClass extends Pdf { //$this->rootPath is in config lle_pdf_generator.path (default:data/pdfmodel) public function init() { $this->setSourceFile($this->rootPath . 'background.pdf'); } public function myColors() { return ['blanc' => 'FFFFFF','default'=> '000000', 'red' => 'FF0000']; } //the fonts is in $this->rootPath.'/fonts' public function myFonts() { return ['titre' => ['size'=>12,'color'=>'noir','family'=>'courier', 'style'=>'BU']]; } public function generate() { $this->AddPage('P'); $this->showGrid(5); //is an debug function which show an gride by 5px $this->changeFont('titre'); $this->w(10,10,'Hello <b>'. $this->data['name'] .'</b>'); } public function footer() { } }
<?php /** * @Route("/pdf") */ public function pdf(PdfGenerator $generator, UserRepository $userRepository) { $data = []; foreach($userRepository->findAll() as $user){ $data[] = ['name' => $user->getName()]; } return $generator->generateByRessourceResponse(TcpdfGenerator::getName(), MyTcpdfClass::class, $data); }
您可以在数据库中创建一个PDF模型,资源为"App\Service\Pdf\MyTcpdfClass",代码为MYTCPDF类型"tcpdf"
<?php /** * @Route("/pdf") */ public function pdf(PdfGenerator $generator, UserRepository $userRepository) { $data = []; foreach($userRepository->findAll() as $user){ $data[] = ['name' => $user->getName()]; } return $generator->generateResponse('MYTCPDF', $data); }
使用word_to_pdf(格式Microsoft Word XML)
创建一个包含"Hello ${name}"的.docx文件/data/pdfmodel/test.docx
<?php /** * @Route("/pdf") */ public function pdf(PdfGenerator $generator, UserRepository $userRepository) { $data = []; foreach($userRepository->findAll() as $user){ $data[] = ['name' => $user->getName()]; } return $generator->generateByRessourceResponse(WordToPdfGenerator::getName(), 'test.docx', $data); }
您可以在数据库中创建一个PDF模型,资源为"test.docx",代码为MYDOC类型"word_to_pdf"
<?php /** * @Route("/pdf") */ public function pdf(PdfGenerator $generator, UserRepository $userRepository) { $data = []; foreach($userRepository->findAll() as $user){ $data[] = ['name' => $user->getName()]; } return $generator->generateResponse('MYDOC', $data); }
您可以使用变量${@img[logo]:100x200}或${@img[logo]}来创建图像。(正则表达式是#^@img[(\w+)](:(\d+)x( \d+))?$#)
$generator->generateResponse('MYDOC', [['logo'=> 'logo.png']]);
搜索到{{lle_pdf_generator.path}}/logo.png,因此默认是data/pdfmodel/logo.png
$generator->generateResponse('MYDOC', [['logo'=> '/logo.png']]);
搜索到/logo.png
https://phpword.readthedocs.io/en/latest/templates-processing.html
##签名PDF
使用Lle\PdfGeneratorBundle\Lib\Signature类,您可以对PDF响应或PdfMerge进行签名
创建签名
openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.crt -out tcpdf.crt
openssl pkcs12 -export -in tcpdf.crt -out tcpdf.p12
<?php $password = '***'; $info = [ 'Name' => 'name', 'Location' => 'location', 'Reason' => 'reason', 'ContactInfo' => 'url', ]; $signature = new Signature($generator->getPath().'cert/tcpdf.crt', $password, $info);
您还可以添加带有签名的绘制
<?php /*...*/ $picture = 'signature.png'; $signature = new Signature($generator->getPath().'cert/tcpdf.crt', $password, $info, $pictur); //or $pos = [ 'w' => 40, //width default 40 'h' => 20, //heght default 20 'x' => 10, //x default pageWidth - w 'y' => 10, //y default pageHeight - (h*2+5) 'p' => 1 //page default last page ]; $signature = new Signature($generator->getPath().'cert/tcpdf.crt', $password, $info, $pictur, $pos);
您还可以添加段或点来创建签名图片
<?php $signature = new Signature($certif, $password, $info); $signature->setSegments([[$x1,$y1],[$x2,$y2]], $pos); //or $signature->setPoints([$x1,$y1,$x2,$y2], $pos); //or $signature->setImage('signe.png', $pos); $signature->setPosition($pos); // you can use it also
PDF响应
<?php return $generator->generateByRessourceResponse(WordToPdfGenerator::getName(), 'test.docx', $data, [$signature]); //or return $generator->generateResponse('MYMODELCODE', $data, [$signature]);
PDF合并
pdfMerge是生成器返回的实例的类
<?php $pdfMerger = $generator->generateByRessource(WordToPdfGenerator::getName(), 'test.docx', $data); //or $pdfMerger = $generator->generate('MYMODELCODE', $data); $pdf = $generator->signes($pdfMerger, [$signature]); //return an TcpdfFpdi (signe($pdfMerger, $signature) exist also) $pdf->Output('My pdf', 'D'); // return a signed pdf $pdfMerger->merge('My pdf', 'D'); // return a unsigned pdf
您不能对pdfMerger进行签名,您必须通过TcpdfFpdi传递。PdfMerger实例永远不能签名
您可以使用$generator->signeTcpdfFpdi($pdf, $signature)继续对TcpdfFpdi进行签名
您还可以直接使用签名实例来对PdfMerger或TcpdfFpdi进行签名。
<?php $pdfMerger = $generator->generate('MYMODELCODE', $data); $signature->signe($pdfMerger)->Output('My pdf', 'D');
或者
<?php $pdfMerger = $generator->generate('MYMODELCODE', $data); $pdf = $pdfMerger->toTcpdfFpdi(); $pdf = $signature->signeTcpdfFpdi($pdf); $pdf = $signature2->signeTcpdfFpdi($pdf); $pdf->Output('My pdf', 'D');
您不能在PdfMerger中使用多个签名。
可迭代数据
创建一个.docx文件并创建2个表格(1行,3列)
- 第一个表格的单元格1写${eleves.nom},单元格2写${eleves.etablissement.nom},单元格3写${@img[eleves.logo]}
- 第二个表格的单元格1写${users.[nom]},单元格2写${users.[adresse][rue]},单元格3写${@img[users.[logo]])
使用Lle\PdfGeneratorBundle\Lib\PdfIterable类将文件保存为myiterable.docx
<?php $data = [ 'eleves' => new PdfIterable($this->em->getRepository(Eleve::class)->findAll()), 'users' => new PdfIterable([['nom'=>'saenger','adresse'=>['rue'=>'rue du chat'], 'logo'=>'logo.png'], ['nom'=>'boehler', 'adresse'=>['rue'=>'rue du chien'], 'logo.png']]), ]; return $generator->generateByRessourceResponse(WordToPdfGenerator::getName(), 'myiterable.docx', $data);
显示它
警告:只有第一层数据可以作为PdfIterable,您不能使用${etablissement.eleves}
<?php $data = [ 'etablissement' => $etablissement, 'eleves' => PdfIterable($etablissement->getEleves()) ];
理解属性(单词转PDF)
属性通过propertyAccesor(Symfony)读取,但第一个位于两个“[]”之间:[first].rest
the vars ${eleve.etablissement.nom} -> $propertyAccess->getValue($params, '[eleve].etablissement.nom')
the vars ${eleve.etablissement[nom]} -> $propertyAccess->getValue($params, '[eleve].etablissement[nom]')
!!!警告:如果创建自己的类型,请使用相同的系统!!!
合并多个模型
<?php return $generator->generateByRessourceResponse( TcpdfGenerator::getName(), [MyTcpdfClass::class,AnotherTcpdfClass::class], $data);
<?php return $generator->generateByRessourceResponse( [TcpdfGenerator::getName(),WortdToPdfGenerator::getName()], [MyTcpdfClass::class,'mydoc.docx'], $data);
在数据库中
INSERT INTO `lle_pdf_model` (`code`, `path`, `type`) VALUES ('RELANCE_1ANS', 'mydoc.docx,App\\Service\\Pdf\\LotInvitation', 'word_to_pdf,tcpdf')
默认类型总是第一个(这里为"word_to_pdf")
如果没有定义任何类型,则类型为lle_pdf_generator.default_generator配置
迁移到pdf生成器v3
在v3中,向后兼容性有少量中断。以下是迁移步骤
@LlePdfGeneratorBundle/Resources/routing/routes.yaml
现在在@LlePdfGeneratorBundle/Resources/config/routes.yaml
- 类
Lle\PdfGeneratorBundle\Entity\PdfModelCustomFileTrait
被Lle\PdfGeneratorBundle\Entity\PdfModelTrait
替代,并且现在特性包含$file
属性 - 路由
lle_pdf_generator_show_ressource
改为lle_pdf_generator_show_model
- 路由
lle_pdf_generator_show_pdf
改为lle_pdf_generator_download_model