Laravel・PHP入門

PHPer初心者

【Laravel】HTMLページをPDF化してダウンロード(TCPDF使用)

Laravelを用いてPDF化したかったのですがパッケージがとても優秀だった。
レイアウトが中身により変動するため、HTMLのページを作成しそれをPDF化することとします。
(そのためFPDIは使用していません。)

環境

Laravel5.5
PHP7.2

TCPDFをインストール

※ 参考
公式GithubGitHub - 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');
コントローラ作成

php artisan make::controller DocumentController

まずはコントローラの作成、次にPDF化するクラスを実装していきます。

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化したシートがダウンロードできるはずです。
f:id:fresh_engineer:20180603135255p:plain

できました!
CSSでの装飾は結構制限かかってるそうですが、
それ以外は最高に手軽ですね。。。
ありがとうTCPDF様、感謝しかない。。。

以上

【#bcu30】BATTLE CONFERENCE UNDER30 2018 公開スライドまとめ

昨日2018.04.21にCyberAgentさん主催の BATTLE CONFERENCE UNDER30に参加してきました!

bcu30.jp

控えめにいってもすごくおもしろくて勉強になりました..!

体感熱いうちに復習したいのですが 同じように探したい方もいらっしゃるかと思いまして 既にTwitterでシェアされていたスライドのリンクをまとめます。 slideshareとspeakerdeckで横幅違うんですね。

運営、登壇者の皆様本当にありがとうございました!

サーバ・インフラ

3. 動画配信サービスとしてこの先生きのこるには by AbemaTV 山中さん

speakerdeck.com

4. U30エンジニアだからこそ実現できた劇的ビフォーアフター by エイチーム 田中さん

speakerdeck.com

7. クラウドサービスの成長とログ基盤の進化 by サイボウズ 上岡さん

www.slideshare.net

6. カバレッジ95%以上を実現したテストコードの書き方 by HRBrain 鈴木さん

speakerdeck.com

5. モンストのサーバー負荷との戦い 〜あけおめ2018編〜 by ミクシィ 浜田さん

speakerdeck.com

11. 事業を伸ばすエンジニアリング by マッチングエージェント 木邑さん

speakerdeck.com

データ

4. ユーザー行動の数理モデルと高速推薦システム by Gunocy 米田さん

speakerdeck.com

5. レコメンドは稼げる by ランサーズ 高田さん

www.slideshare.net

クライアント

3. 先人の亡霊 VS 俺 〜 Rails の JS の場合 〜 リブセンス 鈴木さん

www.slideshare.net

5. 5年間VRゲームを作ってみた by gumi 渡部さん

www.slideshare.net

8. 複数人で高速に開発するための npm モジュール by ソウゾウ 大原さん

speakerdeck.com

9. CASHのユーザビリティを支える(泥臭い)技術 by BANK 熊谷さん

speakerdeck.com

開発プロセス

1. 現場エンジニアが採用活動やってみたお話。by サイボウズ 杉山さん

speakerdeck.com

2. エンジニアが数字を作る開発チームの生まれ方 by リクルートマーケティングパートナーズ 小原さん

speakerdeck.com

随時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のプロジェクトへ変換 ③サーバ起動 →モックサーバとしてブラウザ上での確認、 自分のプロジェクトからもレスポンス確認ができる

良いこと: * Githubyamlファイルのみの管理で良い * コマンド一つでモックサーバが起動する

悪いこと: * 仕様書を書き換えるたびにプロジェクトの上書きが必要 * サーバ必要

前準備(brew/npmは入ってる前提)

@任意のdirで(今回は/Users/ユーザ名/swagger/) * javaのinstall(入っていなければ) brew cask install caskroom/versions/java8

  • swagger-codegenのinstall brew install swagger-codegen

swagger形式のAPI仕様書作成

  • swagger.yamlファイルの作成(名前は任意、api1.yamlなどでもOK) vi swagger.yaml
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
  • swagger codegenコマンドで、yamlファイルから任意のディレクトリ内にモックサーバのプロジェクト生成(今回はnodejsで作ってます)

mkdir codegen-test/

swagger-codegen generate -i swagger.yaml -l nodejs-server -o codegen-test/

codegen-test は任意のディレクトリ名でok

  • プロジェクト生成後、パッケージ諸々インストールして、モックサーバ起動
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の違いでした。。。

ちなみに今は配列でのレスポンス、ファイルの結合とかで苦労してました phpyaml結合ツールつくるしかないかなー とりあえず一連のモックサーバ起動までの流れをshellかこう。

ではまた!

【🔰初心者】【API】RESTfulなAPIのリクエストとレスポンスについて

最近APIの設計について考えることが多かったのでまとめておきます。
※RESTFulとは何か、については言及しません。
あくまでリクエストとレスポンスの設計について言及します。

そもそもAPIとは

まず自分が初心者である時一番わからなかったのがAPIって何ってことでした。
偏見イメージで話すと、アプリケーションとアプリケーションを繋げるアダプタのようなものです。
皆さん例えばパソコンとモニターをつなぐケーブルをお持ちですか?

Amazonベーシック HDMI-DVI 変換ケーブル - 1.8m (タイプAオス- DVI24pinオス)

自分のパソコンが出力できる形と、モニターへ入力できる形って違っていますよね?
それを整形して、繋げてあげるのがケーブル、つまりAPIの役割です。

サーバ側:APIから受け取ったリクエストからデータをAPIに返す
API:特定のリクエストを受け取ってサーバ側に渡す
サーバで処理した後のデータをJSON形式で返す
フロント側:JSONしか受け取らない、APIから帰ってきたデータを整形して表示する

イメージとしてはこんな感じです。
なので、APIを考えるときは、
「どんなリクエストに対して、どんなレスポンスを返す必要があるのか」
を考えます。
多分あんまりわからないと思うので、もう少し具体的に考えてみます。

qiita.com

この記事にめちゃくちゃお世話になりました。ありがとうございます。土下座

例えばよくある、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

  • jQueryでDOM取得して配列で帰ってくる →配列 each ごとにインスタンス化している

  • 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(iPadiPodになるそうで)、後Androidを省けば
大体対応できるようです。海外はわかりませんが

以上