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依赖 // 对于64位系统,使用: composer require h4cc/wkhtmltopdf-amd64 0.12.x composer require h4cc/wkhtmltoimage-amd64 0.12.x
對於homestead開發環境,也要執行:cp vendor/h4cc/wkhtmltoimage-amd64/bin/wkhtmltoimage-amd64 /usr/local/bin/
cp vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64 /usr/local/bin/
chmod +x /usr/local/bin/wkhtmltoimage-amd64
chmod +x /usr/local/bin/wkhtmltopdf-amd64
鍵設定facade別名(可選):
'PDF' => Barryvdh\Snappy\Facades\SnappyPdf::class, 'SnappyImage' => Barryvdh\Snappy\Facades\SnappyImage::class,
最後發布資源檔案:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">php artisan vendor:publish --provider="Barryvdh\Snappy\ServiceProvider"</pre><div class="contentsignin">登入後複製</div></div>
在.env
檔案中新增:
WKHTML_PDF_BINARY=/usr/local/bin/wkhtmltopdf-amd64 WKHTML_IMG_BINARY=/usr/local/bin/wkhtmltoimage-amd64
然後在
snappy.php設定檔中做以下設定:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"> &#39;pdf&#39; => [
&#39;enabled&#39; => true,
&#39;binary&#39; => env(&#39;WKHTML_PDF_BINARY&#39;, &#39;vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64&#39;),
&#39;timeout&#39; => 3600,
&#39;options&#39; => [],
&#39;env&#39; => [],
],
&#39;image&#39; => [
&#39;enabled&#39; => true,
&#39;binary&#39; => env(&#39;WKHTML_IMG_BINARY&#39;, &#39;vendor/h4cc/wkhtmltoimage-amd64/bin/wkhtmltoimage-amd64&#39;),
&#39;timeout&#39; => 3600,
&#39;options&#39; => [],
&#39;env&#39; => [],
],</pre><div class="contentsignin">登入後複製</div></div>
透過載入渲染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');
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 // 导出选定的行
中有:
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);
這裡面的程式碼:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">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方法
}}</pre><div class="contentsignin">登入後複製</div></div>
最關鍵的是
方法,我們將新建一個繼承AbstractExporter
類的類,實現我們自己想要的導出邏輯。另外,看
方法:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">protected function getExporter($scope){
return (new Exporter($this))->resolve($this->exporter)->withScope($scope);}</pre><div class="contentsignin">登入後複製</div></div>
我們也可以在子類別中改寫withScope
進行一些參數設定、攔截。
開始改造導出功能
了解了基本的原理,再參考下Laravel-admin的文檔,我們就可以著手改下導出功能了。 首先,建立一個擴展,如app/Admin/Extensions/PdfExporter.php,程式碼實作如下:
<?php namespace App\Admin\Extensions; use Encore\Admin\Grid\Exporters\AbstractExporter; use Encore\Admin\Grid\Exporter; 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, "\n"), 200, $headers)->send(); exit; } }
接著,在
app/Admin/ bootstrap.php中註冊擴充功能:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Exporter::extend(&#39;pdf-exporter&#39;, PdfExporter::class);</pre><div class="contentsignin">登入後複製</div></div>
最後,對應的在
方法中使用:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">protected function grid(){
// 其他逻辑...
// 添加导出PDF的扩展
$grid->exporter(&#39;pdf-exporter&#39;);
return $grid;}</pre><div class="contentsignin">登入後複製</div></div>這樣,點擊匯出按鈕的時候,就可以下載PDF了。 <p><code>
blade範本中的css、js位址必須是完整的url位址,所以mix( 'css/app.css')應該改為asset('css/app.css')
最後,請貼個效果圖:
以上是如何使用Laravel snappy產生PDF並整合到Laravel-admin的詳細內容。更多資訊請關注PHP中文網其他相關文章!