2018/11 開始了新的專案,這個專案的目標是
- 取得Google Cloud Billing 資料然後整理呈現報表
- 使用者類別有:管理者/經銷商/一般客戶
- 不同類別使用者顯示的 Billing 金額不同,差異為服務費與折扣
主要的架構流程
- 取得每日的 Billing 資料並儲存到 Google BigQuery (Cloud SQL 無法應付每個月千萬筆的資料成長)
- 使用 Google service account & Oauth certification 透過 Google Cloud Platform 取得資料
- 透過 UI 呈現不同的資料分析(Chart / DataTable),提供不同的報表下載(CSV / PDF)
技術規格選用
- Laravel 5.7 (每個新案子都得要用最新的 stable的版本)
- PHP 7
- 第三方的 Library 一堆(這個都交給composer去管理吧)
所有的服務都建構在 Google Cloud Platform 上,包含 Version control。
在 GCE與GAE的選擇上做了些研究,最後選擇了GAE。理由很簡單,就是為了 Flexible。
整個案子很多環節遇到了很多問題,但是一開始的問題就是 Laravel 的安裝,GAE不像是 GCE 可以自由地瀏覽空間中的檔案並且及時修改。Deploy上去後就無法看到或是管理任何的檔案,而且最讓人困擾的就是每次的 Deploy 都要花上5-10分鐘,所以只要一次的疏忽就得要重新來一次,非常的浪費時間。
laravel 5.7 + composer 1.8.0 + phpstorm 2018.1.16
下面就透過步驟來展示
deploy log 會以文字訊息的方式顯示。
部署完成後執行
就可以測試 laravel 是否安裝成功
上面展示了 laravel 部署到 GAE的方式,也說明了 dompdf 中文字型的安裝方式,其餘開發上的問題都可以直接閱讀 laravel / composer / dompdf 官網文件來解決了。
希望大家可以透過我的分享省去些摸索的時間。
參考資料
所以文章主要將問題簡單的拆分兩個,這兩個解決了,其他都可以參考個別的技術文件去學習。
- Laravel 的安裝與設定
- PDF 中文字型的安裝 (dompdf)
Laravel 的安裝與設定
laravel 5.7 + composer 1.8.0 + phpstorm 2018.1.16
下面就透過步驟來展示
使用 phpstorm 建立 laravel 專案
開啟 phpstorm > New project > Composer project ,Package 選擇 laravel/laravel 然後點選 create
你也可以只使用 composer 就可以完成
在根目錄下新增 app.yaml 檔案
這個檔案用於 GAE 的環境設定,也是唯一可以設定 GAE的方法,不需要懷疑,因為沒有其他方法了。修改 app.yaml
直接把所有 .env 的設定都移到這個檔案來,下面我直接把說明備註在後面
runtime: php #php版本設定,在撰寫這篇文章的時候 php72 無法設定 env_variables env: flex #GAE flexible選用 runtime_config: document_root: public #網站根目錄設定, laravel 是public composer_flags: --no-dev # composer 設定不安裝開發用套件 env_variables: # 下面都是 laravel 的環境設定,也就是說將需要在 .env 的設定都搬來這裡 APP_KEY: 'base64:hWWKPKQ6u48Cn8lw4WM00UHdCEQJerEQk5ognsy4u' # 必須使用 artisan 產生後複製過來 APP_LOG: errorlog STORAGE_DIR: /tmp #GAE上除了 tmp 目錄外都只會有 readonly 權限 APP_NAME: "[BETA]GCPBS| Summer " APP_ENV: production APP_DEBUG: true CACHE_DRIVER: database SESSION_DRIVER: database GCP_PROJECT_ID: 'summer-digital.com' GCP_PROJECT_BUCKET_ID: 'summer-digital.appspot.com'
GCP_BILLING_DATASET_NAME: 'summer-digital.com.billing-history'
GCP_CLIENT_SECRET: '/resources/gcp/summer-client-secret.json' GCP_SERVICE_ACCOUNT_CREDENTIAL: '/resources/gcp/summer-service-account.json' DB_CONNECTION: mysql DB_HOST: localhost DB_PORT: 3306 DB_DATABASE: summer DB_USERNAME: summer DB_PASSWORD: summer DB_SOCKET: "/cloudsql/summer:asia-northeast1: summer-production"
修改 composer
deploy 後我們必須對 laravel 作 cache 的清理,否則會出現路徑上的問題,但是無法操作GAE所以只能透過 composer scripts 來代勞,在 composer.json 中新增下面的 scripts。GAE在 deploy後會執行 composer install,所以下面的 script 可以幫我們清理 laravel 的cache。"scripts": { "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover", "@php artisan config:cache", "@php artisan view:clear"]
}
部署到 GAE
執行指令前必須安裝 Gcloud SDK,而且需要設定 GCP。部署只需在 Terminal 執行下面指令
YUCHANs-MBP:~ yuchanlin$ gcloud app deploy
deploy log 會以文字訊息的方式顯示。
部署完成後執行
YUCHANs-MBP:~ yuchanlin$ gcloud app browse
PDF 中文字型的安裝 (dompdf)
PDF我透過 composer 安裝使用 dompdf 0.8.3 的版本,但是安裝後本身並無中文字型,所以必須要透過下面步驟安裝字型才能正常的顯示中文。
- dompdf 0.8.3
- dompdf util load_font.php
- Google Fonts 的思源體
下載上方的資源體字型檔案,必須是 TTF 格式,然後到下面的位置
- storage/fonts/NotoSansTC-Medium.ttf
- storage/fonts/NotoSansTC-Bold.ttf
下載字型安裝工具
下載 load_font.php 然後放到 laravel 目錄下
開啟 Terminal 然後到 load_font.php 目錄下執行下面指令
php load_font.php storage/fonts/NotoSansTC-Medium.ttf storage/fonts/NotoSansTC-Bold.ttf
執行完成後,會將字型安裝到 dompdf/lib/fonts 中,在 html 裡頭就可以透過 css 設定中文字型:
body { font-family: 'notosanstc'; font-size: 16px; color: #555e6b; }
設定 composer
因為部署不會把 vendor 上傳上去,有兩個原因
- GAE限制 deploy 的檔案限制是 100,00
- 把 vendor 上傳上去需要花很多時間,很浪費時間
所以需要透過 composer scripts 在 install 後幫忙安裝字型檔案
"scripts": { "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover", "@php artisan config:cache", "@php artisan view:clear", "@php load_font.php 'notosanstc' storage/fonts/NotoSansTC-Medium.ttf storage/fonts/NotoSansTC-Bold.ttf" ] }
下面的範本包含圖檔的處理與產生PDF的設定:
$arrContextOptions = array( "ssl" => array( "verify_peer" => false, "verify_peer_name" => false, ),); $type = pathinfo($logoUrl, PATHINFO_EXTENSION);$avatarData = file_get_contents($logoUrl, false, stream_context_create($arrContextOptions));$avatarBase64Data = base64_encode($avatarData);$imageData = 'data:image/' . $type . ';base64,' . $avatarBase64Data; $html = view('export/html', compact('table', 'currency', 'total', 'logoUrl', 'imageData', 'billingName', 'firstDay', 'lastDay', 'time', 'businessSupport', 'discount', 'paymentDueDay')) ->render(); $options = new Options();$options->setIsHtml5ParserEnabled(true);$options->setIsPhpEnabled(true);$options->setIsRemoteEnabled(true);$options->setIsJavascriptEnabled(true); $dompdf = new Dompdf($options);$dompdf->setPaper('A4', 'portrait'); $dompdf->loadHtml($html, 'utf8');$dompdf->render();$dompdf->stream($downloadFileNmae . '.pdf', ['compress' => 1, 'Attachment' => 1]);
希望大家可以透過我的分享省去些摸索的時間。
參考資料