视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
如何使用Laravel snappy生成PDF并集成到Laravel-admin
2020-11-02 18:28:10 责编:小采
文档

下面由Laravel教程栏目给大家介绍使用Laravel snappy生成PDF并集成到Laravel-admin的方法,希望对需要的朋友有所帮助!

Laravel snappy

之前使用过python+wkhtmltopdf来导出PDF,wkhtmltopdf确实是很强大的工具,有很多的页面定制选项,而且会自动帮你把网上的图片抓取下来,渲染到PDF上。这次想在Laravel-admin中实现导出PDF的功能,于是找到了Laravel snappy这个扩展包,它是对https://github.com/KnpLabs/snappy这个项目的封装,好巧的是,它也是通过调用wkhtmltopdf程序来生成PDF的。

安装与配置

// 安装扩展包
composer require barryvdh/laravel-snappy

// 将wkhtmltopdf作为composer依赖
// 对于位系统,使用:
composer require h4cc/wkhtmltopdf-amd 0.12.x
composer require h4cc/wkhtmltoimage-amd 0.12.x

对于homestead开发环境,还要执行:

cp vendor/h4cc/wkhtmltoimage-amd/bin/wkhtmltoimage-amd /usr/local/bin/
cp vendor/h4cc/wkhtmltopdf-amd/bin/wkhtmltopdf-amd /usr/local/bin/

chmod +x /usr/local/bin/wkhtmltoimage-amd 
chmod +x /usr/local/bin/wkhtmltopdf-amd

安装完后,在app.configalias键设置facade别名(可选):

'PDF' => BarryvdhSnappyFacadesSnappyPdf::class,
'SnappyImage' => BarryvdhSnappyFacadesSnappyImage::class,

最后发布资源文件:

php artisan vendor:publish --provider="BarryvdhSnappyServiceProvider"

.env文件中添加:

WKHTML_PDF_BINARY=/usr/local/bin/wkhtmltopdf-amd
WKHTML_IMG_BINARY=/usr/local/bin/wkhtmltoimage-amd

然后在snappy.php配置文件中做如下配置:

 'pdf' => [
 'enabled' => true,
 'binary' => env('WKHTML_PDF_BINARY', 'vendor/h4cc/wkhtmltopdf-amd/bin/wkhtmltopdf-amd'),
 'timeout' => 3600,
 'options' => [],
 'env' => [],
 ],

 'image' => [
 'enabled' => true,
 'binary' => env('WKHTML_IMG_BINARY', 'vendor/h4cc/wkhtmltoimage-amd/bin/wkhtmltoimage-amd'),
 'timeout' => 3600,
 'options' => [],
 'env' => [],
 ],

使用

通过加载渲染blade模板生成PDF:

$pdf = PDF::loadView('pdf.invoice', $data); //pdf.invoice是你的blade模板
return $pdf->download('invoice.pdf');

通过外部链接生成:

return PDF::loadFile('http://www.github.com')->inline('github.pdf');

通过html生成,并做各种设置,并保存之:

PDF::loadHTML($html)->setPaper('a4')->setOrientation('landscape')->setOption('margin-bottom', 0)->save('myfile.pdf')
// 更多选项可查看wkhtmltopdf的手册:https://wkhtmltopdf.org/usage/wkhtmltopdf.txt

Laravel-admin导出功能改造

Laravel-admin默认的导出格式是csv,这里将把它改造成想要的PDF格式。

Laravel-admin导出原理简单分析

查看导出按钮,可得到这三个导出入口格式大概如下:

http://hostname/posts?_export_=all // 导出全部
http://hostname/posts?_export_=page%3A1 // 导出当前页
http://hostname/posts?_export_=selected%3A1 // 导出选定的行

其有对应的控制器方法应该是index,从这里追查开去,可以找到/vendor/encore/laravel-admin/src/Grid.php中有:

public function render(){
 $this->handleExportRequest(true); 
 try {
 $this->build();
 } catch (Exception $e) {
 return Handler::renderException($e);
 }
 $this->callRenderingCallback();
 return view($this->view, $this->variables())->render();}

如果url中有带_export=…参数,将会执行$this->handleExportRequest(true);这里面的代码:

protected function handleExportRequest($forceExport = false){
 if (!$scope = request(Exporter::$queryName)) {
 return;
 }

 // clear output buffer.
 if (ob_get_length()) {
 ob_end_clean();
 }

 $this->disablePagination();

 if ($forceExport) {
 $this->getExporter($scope)->export(); // 这里将调用某个类的export方法
 }}

最关键的是export方法,我们将新建一个继承AbstractExporter类的类,实现我们自己想要的导出逻辑。另外,看getExporter方法:

protected function getExporter($scope){
 return (new Exporter($this))->resolve($this->exporter)->withScope($scope);}

我们还可以在子类中改写withScope进行一些参数设置、拦截。

开始改造导出功能

了解了基本的原理,再参考下Laravel-admin的文档,我们就可以着手改下导出功能了。

首先,创建一个扩展,如app/Admin/Extensions/PdfExporter.php,代码实现如下:

<?php

namespace AppAdminExtensions;

use EncoreAdminGridExportersAbstractExporter;
use EncoreAdminGridExporter;
use PDF;

class PdfExporter extends AbstractExporter
{
 protected $lackOfUserId = false;

 public function withScope($scope){
 // 你自己的一些处理逻辑,比如:
 /*if ($scope == Exporter::SCOPE_ALL) {
 if(request()->has('user_id')) {
 $this->grid->model()->where('user_id', request()->user_id);
 } else {
 $this->lackOfUserId = true;
 }
 return $this;
 }*/
 return parent::withScope($scope);
 }

 public function export()
 {
 // 具体的导出逻辑,比如:
 if($this->lackOfUserId) {
 $headers = [
 'Content-Encoding' => 'UTF-8',
 'Content-Type' => 'text/html;charset=UTF-8',
 ];
 response('请先筛选出用户', 200, $headers)->send();
 exit();
 }
 $author = $this->grid->model()->getOriginalModel()->first()->user->user_name;

 $this->grid->model()->orderBy('add_time', 'desc');

 // 按年-月分组数据
 $data = collect($this->getData())->groupBy(function ($post) {
 return Carbon::parse(date('Y-m-d',$post['add_time']))->format('Y-m');
 })->toArray();
 // 渲染数据到blade模板
 $output = PDF::loadView('pdf.weibo', compact('data'))->setOption('footer-center', '[page]')->output();

 $headers = [
 'Content-Type' => 'application/pdf',
 'Content-Disposition' => "attachment; filename=$author.pdf",
 ];

 // 导出文件,
 response(rtrim($output, "
"), 200, $headers)->send();

 exit;
 }
}

接着,在app/Admin/bootstrap.php中注册扩展:

Exporter::extend('pdf-exporter', PdfExporter::class);

最后,对应的在Grid方法中使用:

protected function grid(){
 // 其他逻辑...

 // 添加导出PDF的扩展
 $grid->exporter('pdf-exporter');
 return $grid;}

这样,点击导出按钮的时候,就可以下载PDF了。

注意事项

  • blade模板中的css、js地址必须是完整的url地址,所以mix('css/app.css')应该改为asset('css/app.css')
  • 图片地址最好使用http协议代替https,比较不容易出错
  • 最后,贴个效果图吧:

    下载本文
    显示全文
    专题