【Laravel】HTMLページをPDF化してダウンロード(TCPDF使用)
Laravelを用いてPDF化したかったのですがパッケージがとても優秀だった。
レイアウトが中身により変動するため、HTMLのページを作成しそれをPDF化することとします。
(そのためFPDIは使用していません。)
環境
Laravel5.5
PHP7.2
TCPDFをインストール
※ 参考
公式Github:GitHub - tecnickcom/TCPDF: Official clone of PHP library to generate PDF documents and barcodes
tecnick.com/tcpdf - Packagist
念の為Packagistを確認すると、2018年2月時点で6.2.17が最新だそうです。
なので、composer.jsonのrecuire配下に下記を書き込む
"tecnickcom/tcpdf": "6.2.*"
そのあとインストールする。
composer update
もちろんcomposer require~でも大丈夫です
Package manifest generated successfully.
とででくればインストール完了です!
TCPDFでPDF化
ルーティング
コントローラでこの後実装するメソッドへのルーティングを作成します。
route/web.php
<?php /* PDF TEST */ Route::get('/pdf/test', 'DocumentController@downloadPdf');
PDF化するためのHTMLページ作成
次に、HTMLページで描画したあとPDF化したいので、HTMLページを事前準備します。
結構適当で大丈夫ですが、今回日本語、変数のテストをしたかったので
下記で作成してみました。
/resources/views/document/pdf.blade.php
<!doctype html> <html lang="{{ config('app.locale') }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>PDF TEST</title> </head> <body> <p>あいうえお漢字</p><br> <p>Hello, {{ $name }}</p> </body> </html>
PDF化機能の実装
/Controllers/DocumentController.php
<?php namespace App\Http\Controllers; use TCPDF; class DocumentController extends Controller { private $pdf; // インスタンス変数を宣言 public function __construct(TCPDF $pdf) { // コンストラクタインジェクションでTCPDFクラスをインスタンス化 $this->pdf = $pdf; } public function downloadPdf() { // フォント、スタイル、サイズ をセット $this->pdf->setFont('kozminproregular','',10); // ページを追加 $this->pdf->addPage(); // HTMLを描画、viewの指定と変数代入 $this->pdf->writeHTML(view("document.pdf", ['name' => 'PDFさん'])->render()); // 出力の指定です、ファイル名、拡張子、Dはダウンロードを意味します。 $this->pdf->output('test' . '.pdf', 'D'); return; } }
ここまでくれば実装完了です。
使ってみる
php artisan serveでサーバを起動し、ルーティングで指定した
ルートへアクセスしてみます。http://127.0.0.1:8000/pdf/test'
問題なければ、PDF化したシートがダウンロードできるはずです。
できました!
CSSでの装飾は結構制限かかってるそうですが、
それ以外は最高に手軽ですね。。。
ありがとうTCPDF様、感謝しかない。。。
以上
【#bcu30】BATTLE CONFERENCE UNDER30 2018 公開スライドまとめ
昨日2018.04.21にCyberAgentさん主催の BATTLE CONFERENCE UNDER30に参加してきました!
控えめにいってもすごくおもしろくて勉強になりました..!
体感熱いうちに復習したいのですが 同じように探したい方もいらっしゃるかと思いまして 既にTwitterでシェアされていたスライドのリンクをまとめます。 slideshareとspeakerdeckで横幅違うんですね。
運営、登壇者の皆様本当にありがとうございました!
サーバ・インフラ
3. 動画配信サービスとしてこの先生きのこるには by AbemaTV 山中さん
4. U30エンジニアだからこそ実現できた劇的ビフォーアフター by エイチーム 田中さん
7. クラウドサービスの成長とログ基盤の進化 by サイボウズ 上岡さん
www.slideshare.net
6. カバレッジ95%以上を実現したテストコードの書き方 by HRBrain 鈴木さん
5. モンストのサーバー負荷との戦い 〜あけおめ2018編〜 by ミクシィ 浜田さん
11. 事業を伸ばすエンジニアリング by マッチングエージェント 木邑さん
データ
4. ユーザー行動の数理モデルと高速推薦システム by Gunocy 米田さん
5. レコメンドは稼げる by ランサーズ 高田さん
www.slideshare.net
クライアント
3. 先人の亡霊 VS 俺 〜 Rails の JS の場合 〜 リブセンス 鈴木さん
www.slideshare.net
5. 5年間VRゲームを作ってみた by gumi 渡部さん
www.slideshare.net
8. 複数人で高速に開発するための npm モジュール by ソウゾウ 大原さん
9. CASHのユーザビリティを支える(泥臭い)技術 by BANK 熊谷さん
開発プロセス
1. 現場エンジニアが採用活動やってみたお話。by サイボウズ 杉山さん
2. エンジニアが数字を作る開発チームの生まれ方 by リクルートマーケティングパートナーズ 小原さん
随時upお見かけしたら追加します。 bcu来年も参加したい!本当にありがとうございました!
【API】【Swagger】Swaggerをモックサーバとして機能させるまで
今回、サーバ・フロントの完全分業実現のため Swaggerを導入し、APIの仕様を管理、かつモックサーバとして機能させることに。
仕様を決める→モックサーバとして動作させるまでの流れメモ。
動作確認環境
Mac OS X以上 Swagger2.0 (Open APIは3.0が最新ですがswagger-codegen使用のため2.0を使用) はやく3.0対応してほしみ。。。
流れ
※色々インストールなどの前準備※ ①API仕様をSwagger形式(yaml)で記載、 ②Swagger-Codegenを使用してnode.jsのプロジェクトへ変換 ③サーバ起動 →モックサーバとしてブラウザ上での確認、 自分のプロジェクトからもレスポンス確認ができる
良いこと: * Githubでyamlファイルのみの管理で良い * コマンド一つでモックサーバが起動する
悪いこと: * 仕様書を書き換えるたびにプロジェクトの上書きが必要 * サーバ必要
前準備(brew/npmは入ってる前提)
@任意のdirで(今回は/Users/ユーザ名/swagger/)
* javaのinstall(入っていなければ)
brew cask install caskroom/versions/java8
- swagger-codegenのinstall
brew install swagger-codegen
swagger形式のAPI仕様書作成
swagger: '2.0' // モックのメタデータを記述する info: description: | This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). version: 1.0.0 title: Swagger Petstore license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html // モックサーバーのプロトコルの選択 schemes: - http // エンドポイントの記述 paths: /pet/{petId}: get: tags: - pet summary: Find pet by ID description: Returns a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: 200: description: successful operation schema: $ref: '#/definitions/Pet' 400: description: Invalid ID supplied 404: description: Pet not found // モデル定義の記述 definitions: Category: type: object // モデルの詳細定義 properties: id: type: integer format: int64 name: type: string Tag: type: object properties: id: type: integer format: int64 name: type: string Pet: type: object required: - name - photoUrls properties: id: type: integer format: int64 category: $ref: '#/definitions/Category' name: type: string # 各値の例の記述 example: doggie photoUrls: type: array items: type: string tags: type: array items: $ref: '#/definitions/Tag' status: type: string description: pet status in the store enum: - available - pending - sold
mkdir codegen-test/
swagger-codegen generate -i swagger.yaml -l nodejs-server -o codegen-test/
- プロジェクト生成後、パッケージ諸々インストールして、モックサーバ起動
cd codegen-test npm install node index.js
Your server is listening on port 8080 (http://localhost:8080) Swagger-ui is available on http://localhost:8080/docs
こんなレスポンスが帰って来れば、localhost:8080/docsへアクセスすれば swagger-ui上でテストできます!
一度作った仕様書も、更新した後はもう一度node.jsファイルへ変換してあげれば 既に作ったプロジェクトの中身が全部更新されます
OpenAPI3.0になるとかなり変わるので、 今度そのあたりもまとめたいなー かなりハマったのが2.0と3.0の違いでした。。。
ちなみに今は配列でのレスポンス、ファイルの結合とかで苦労してました phpでyaml結合ツールつくるしかないかなー とりあえず一連のモックサーバ起動までの流れをshellかこう。
ではまた!
【🔰初心者】【API】RESTfulなAPIのリクエストとレスポンスについて
最近APIの設計について考えることが多かったのでまとめておきます。
※RESTFulとは何か、については言及しません。
あくまでリクエストとレスポンスの設計について言及します。
そもそもAPIとは
まず自分が初心者である時一番わからなかったのがAPIって何ってことでした。
偏見イメージで話すと、アプリケーションとアプリケーションを繋げるアダプタのようなものです。
皆さん例えばパソコンとモニターをつなぐケーブルをお持ちですか?
自分のパソコンが出力できる形と、モニターへ入力できる形って違っていますよね?
それを整形して、繋げてあげるのがケーブル、つまりAPIの役割です。
サーバ側:APIから受け取ったリクエストからデータをAPIに返す
API:特定のリクエストを受け取ってサーバ側に渡す
サーバで処理した後のデータをJSON形式で返す
フロント側:JSONしか受け取らない、APIから帰ってきたデータを整形して表示する
イメージとしてはこんな感じです。
なので、APIを考えるときは、
「どんなリクエストに対して、どんなレスポンスを返す必要があるのか」
を考えます。
多分あんまりわからないと思うので、もう少し具体的に考えてみます。
この記事にめちゃくちゃお世話になりました。ありがとうございます。土下座
例えばよくある、usersというリソースのCRUD処理について考えます。
/users(単数形)についてRESTfulなAPIを考える
まずは、単純な単数形で考えます。あくまで一例です。
レスポンスなどは特にベストプラクティスではありませんのでご注意ください。
▼CREATE
Request:POST /users
Response:201 CREATEしたuserリソース
ユーザは基本的に、createしたあとは自分の入力データがちゃんと保存されたかどうか?
という答えを求めるます。なので、成功レスポンスにはリソースを含める必要がありますね。
▼READ
Request:GET /users/{userId}
Response:200 要求したリソース(指定idのuserリソース)
ユーザは指定IDのuserを要求しており、今回は要求されたリソースを返します。
▼UPDATE
Request:PUT /users/{userId}
Response:201 UPDATEしたuserリソース
CREATEと同様、ユーザは自分の入力データがちゃんと更新できたかどうか?
を求めています。なので、成功レスポンスにリソースを含めます。
▼DELETE
Request:DELETE /users/{userId}
Response:204 NoContent
削除したあと、自分がどんなデータを削除したか気にしたことがあるでしょうか?
ユーザは削除に成功したかどうかは求めますが、
DELETEは中身を必要としないケースが多いです。
今回も同様のため、204でリソースを含んでいません。
こんな感じです。
ただ、複数形になるとそれはそれで変わります。(これも一例)
/users(複数形)についてRESTfulなAPIを考える
単数と複数で、何が変わりますか?
リクエストもしかり、(例えば一括削除なんかはどうでしょうか?)
レスポンスもしかりですね。
なぜなら、100件をCREATEした時に、100件がCREATEされたかどうかをきにする人はいたとしても、
100件のリソース全てをチェックしたいと思うユーザはどれほどいるでしょうか?
それを踏まえて、同様にAPIを考えてみます。
▼CREATE
Request:POST /users/create
Response:204 No Content
上に書いた内容と同様で、100件など多くの一括操作は中身を求めません。
▼READ
Request:GET /users
Response:200 要求したリソース(user一覧のリソース)
user一覧を要求し、それに対してuser一覧を返します。
▼UPDATE
Request:POST /users/update
Response:204 No Content
CREATEと同様ですね
POSTリクエストのbodyに、どのデータをどうupdateするのか
を含めます。
▼DELETE
Request:POST /users/delete
Response:204 NoContent
POSTリクエストのbodyに、どのデータをdeleteするのか
を含めます。
参考URL
http://www.atmarkit.co.jp/ait/articles/1511/19/news022_3.html
https://developer.cybozu.io/hc/ja/categories/200147600-kintone-API
https://developer.github.com/v3/
http://doc.ec-cube.net/api_policy
以上
APIについては色々意見があると思いますが
ざっくり今日考えたのはこんな感じ。
ではまた!
【JavaScript】メモ
サーバサイドエンジニアがフロントエンドエンジニアに 色々質問してきたのでそのまとめ。
webpackのお仕事
ES6 → ES5にコンパイルしている 1~2年前ES6非対応ブラウザが多く、それらに対応するため
indexファイルにまとめている import/exportなどファイル別だったのに なぜ一つにするのか? →ファイルを分けると、HTTPリクエストがとんで重くなるから
コンポーネント/クラス
いつも実装着手するとき、何を考えてますか? →コンポーネントを考える
例えば〜一覧の例だと、indexTableっていう一覧テーブルを 一つのコンポーネントとして考える
component // クラス定義 クラスの名前、ファイルの名前とまとめて各
小さいコンポーネント? →3つの選択肢から選ぶセレクトボックスとか
ルートコンポーネント// indexPage は 1つのページに1つしかない ルートコンポーネント.find('');
jQuery
DOM操作はすごく重い DOM操作 = getElementbyId("")など なので、高速化のために今業務では innerhtmlで全部ぶちこんでる
関数について
$(() => { });
これは
document.ready(() => { });
と同意義
なので、例えば
$(() => { }); $(() => { });
などを同じファイルで繰り返していると、無意味
グローバル空間について
全部に影響する、$(() => {});などでくくられていない空間のこと window は全て、あらゆるもの情報を持っている
関数の中で、変数をdefineすればその空間のみ、 グローバル空間に影響NGのため、即時関数で実行していた 今はwebpackがやってくれているので グローバル空間は無視してok
セレクタについて
取得の仕方ってどうやってますか? idで取ってくるのが一番はやいのでid最優先、 1ページにいくつもでてくるようであればクラス指定をする。
.on('click')と.click()について
.on('click')は後からappendされた要素も対応するが .click()は対応しないので、 基本的にはon('click')しか使わない
$(div .classA)など複数指定のやつ
両方探すのに時間かかるので、 div.find(classA)など絞ってからにする
※このあたりは、 jQuery高速化で調べればでてくる
thisについて
ES5→ES6で、thisの意味が変わった
ES5 は例えばイベントが起これば、 そのイベントまるごとのことをthisと指していた ES6ではthisは一つ外側を指している。 イメージでいくとphpのクラス。
そのお陰で、外側のプロパティにアクセスしやすくなった
【Laravel/PHP】NULLや空文字列の判定まとめ
業務でNULL判定よく使うのでまとめ。
# 判定表
Laravel内で使っているときは
定義されていることが前提の条件文でエラーをはく。
Laravel5.5 + PHP7.1
未定義 | NULL | 0 | 空 | |
---|---|---|---|---|
if($a) | error | false | false | false |
if($a == NULL) | error | true | true | true |
if($a === NULL) | error | true | false | false |
if($a == 0) | error | true | true | true |
if($a === 0) | error | false | true | false |
if($a == "") | error | true | true | true |
if($a === "") | error | false | false | true |
is_null($a) | error | true | false | false |
isset($a) | false | false | true | true |
empty($a) | true | true | true | true |
例えば
<?php public function is_null() { if($a) { return "aだ"; } return "aではない"; }
これを実行すると、Undefined variable: a
が返る。三項演算子も同様。
その代わり、
<?php public function is_null() { if(isset($a)) { return "aは存在する"; } return "aは存在しない"; }
これを実行しても、"aは存在しない"がかえる。
issetはそもそも定義されているかどうかを判別するメソッドだからだ。
ちなみにLaravelでなく、PHPベタだとレスポンスが変わる
未定義 | NULL | 0 | 空 | |
---|---|---|---|---|
if($a) | false | false | false | false |
if($a == NULL) | true | true | true | true |
if($a === NULL) | true | true | false | false |
if($a == 0) | true | true | true | true |
if($a === 0) | false | false | true | false |
if($a == "") | true | true | true | true |
if($a === "") | false | false | false | true |
is_null($a) | true | true | false | false |
isset($a) | false | false | true | true |
empty($a) | true | true | true | true |
undefinedには気をつけましょう
【Laravel】ユーザの使用端末がPCかスマホか判定する(PHP)
PCとスマホで
表示項目やバリデーションを場合分けしたかったので。
Requestインスタンスが
端末のデータを持ってくれている!
そこから、大概のスマートフォンの情報のみを省いて
場合分けする。
このUser-Agentが持ってるらしい。
'agent' => $request->header('User-Agent')
なので、これを使って場合分け。
<?php ... /** * クライアントの使用端末がMobileかPCか判定 * * @param $request * @return string * @access private */ private function isMobileOrPc($request): string { $user_agent = $request->header('User-Agent'); if ((strpos($user_agent, 'iPhone') !== false) || (strpos($user_agent, 'iPod') !== false) || (strpos($user_agent, 'Android') !== false)) { return 'mobile'; } else { return 'pc'; } }
どうやら、iPoneとiPod(iPadはiPodになるそうで)、後Androidを省けば
大体対応できるようです。海外はわかりませんが
以上