このエントリーをはてなブックマークに追加

7月に大阪で行われたPHPカンファレンス関西2018にて、「すばやく実装するための戦略とテクニック」というタイトルで発表してきました。

内容について

スライド: サンプルコード: https://github.com/77web/phpkansai2018-hellopage

※ 当日にSlideShareでスライドを公開しましたが、PDFをアップロードしたにも関わらず全画面表示にしないと文字が出ないという問題が発生し、SlideShareのサポートに問い合わせてもやる気ない返答が返ってきたので、改めてSpeakerdeckに公開しました。

準備について

この発表は、同僚からのリクエストで実現したものでした。PHPカンファレンス関西に行きたいなーと思い、「なにか聞きたいネタありますか?」とSlackで聞いたところ「これが聞きたい」と出てきたものです。(カルテット開発部には勉強会・カンファレンスの交通費補助制度があり、支給される条件タイプの1つとして「発表する」というものがあります :sweat_smiles: )

当日の発表の中でも言いましたが、普段チームの皆から「速さ」を認めてもらい、頼りにしてもらって仕事をしているので、皆にコツや気をつけていることを伝えられるように発表内容を練りました。
今までLTメインで出ていたので割とぶっつけ本番で発表することが多かったのですが、今回ははじめての30分セッションということで、何回も社内で発表練習をさせてもらい、フィードバックを受けながら完成させました。

当日

前夜祭でinterfaceとレイヤーアーキテクチャについて発表した方がいたり、同じ時間枠の他のセッションでinterfaceの話をする方がいたり、「PHP界にinterfaceブームが来ている…!?」とワクワクしながら朝の新幹線に乗って大阪に向かいました。

1個前の発表から結構入れ替わりがあったにも関わらず、発表開始時点で満員になっており、立ち見で聞いてくださった方もいたほどで、感謝感激です。
今回はじめて発表中にデモを入れたため、途中画面切り替えに失敗するハプニングもありましたが、なんとか最後まで喋りきることができました。

発表後も久しぶりの師匠や知人に会い、色々な話を聞いて、とても楽しく刺激的な一日になりました。

まとめ

PHPカンファレンス関西には何回か行っていますが、今回特に「いいな」と思ったのは実行委員会の方から発表中の写真を送ってもらえたことです。
登壇者には嬉しいサービスだと思います。

大阪は東京に比べて近いですし、また来年も行きたいです! (あるいはPHPカンファレンス名古屋…?)


このエントリーをはてなブックマークに追加

はじめに

Symfonyの Dotenvコンポーネント を使うと、.env というファイルに環境変数を定義しておくことで、アプリケーション内から getenv() $_ENV $_SERVER などを通してその環境変数にアクセスできるようになります。

Symfony 3.3以上ではフレームワークにビルトインされており、Syfmonyアプリケーションのdev環境では .env ファイルを使って環境変数を設定することができるようになっています。

この記事でお伝えすること

今回、.env ファイルで 値に改行文字を含む ような環境変数を設定したい状況に遭遇し、方法を調べましたので、小ネタですが記事として残しておきたいと思います。

結論

symfony/dotenvのテストコード を見てみたら、知りたいことがほぼ全て書かれていました :+1:

複数行に渡る文字列を1つの環境変数にセットしたい場合

結論としては、以下のようにすれば複数行に渡る文字列を1つの環境変数にセットできます。

FOO="a
b
c"

これで、FOO 環境変数に

a
b
c

という値がセットされます。

"" で囲む代わりに '' でも同じことができないのかな?と思い、テストケースの中にはなかったので手元で実験してみたところ、Missing quote to end the value というエラーになってダメでした。

さらにその中に \n という文字列を含ませたい場合

これはちょっとレアなケースかもしれませんが、例えば以下のような文字列を環境変数にセットしたい場合、少し話がややこしくなります。

{
  "private_key": "-----BEGIN PRIVATE KEY-----\naaaaa\nbbbbb\nccccc\nddddd\neeeee\n-----END PRIVATE KEY-----\n"
}

この場合、"\" とエスケープしなければならないのは分かるとしても、その上で先ほどのように単純に

JSON="{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----\naaaaa\nbbbbb\nccccc\nddddd\neeeee\n-----END PRIVATE KEY-----\n\"
}"

としてしまうと、文字列の中に含まれる \n が展開されてしまい、JSON 環境変数の値は

{
  "private_key": "-----BEGIN PRIVATE KEY-----
aaaaa
bbbbb
ccccc
ddddd
eeeee
-----END PRIVATE KEY-----
"
}

となってしまいます。これではJSONとしてパースできません。\n は文字列として値の中に残したいのです。

文字列連結を使う

symfony/dotenvのテストケースのこの部分 を見ると、文字列の連結ができるようです。

また、この辺り を見る限り、""'' の使い分けは、PHPの文字列リテラルと同様、"" では \n が展開されて改行文字として出力され、'' では展開されずそのまま \n が出力されるようです。

というわけで、今回のケースでは以下のように書けば意図したとおりの文字列を環境変数にセットできます。

JSON="{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----"'\n'"aaaaa"'\n'"bbbbb"'\n'"ccccc"'\n'"ddddd"'\n'"eeeee"'\n'"-----END PRIVATE KEY-----"'\n'"\"
}"

ちょっと分かりにくいですが、要するに以下の文字列を連結しているわけです。\n の部分のみ "" ではなく '' で囲んであるので、改行文字に展開されずにそのまま出力できるというわけです。

"{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----"
'\n'
"aaaaa"
'\n'
"bbbbb"
'\n'
"ccccc"
'\n'
"ddddd"
'\n'
"eeeee"
'\n'
"-----END PRIVATE KEY-----"
'\n'
"\"
  }"

おわりに

最後に改めて結論をまとめておきます。

  • 複数行に渡る文字列を環境変数にセットしたい場合は、"" で囲んで普通に改行しちゃえばOK
  • 文字列中に " という文字列を含みたい場合は \" とエスケープする
  • 文字列中に \n という文字列を含みたい場合は、その前後で文字列を切って、\n だけは '' で囲む形にして、連結する
    • 実践的には、\n"'\n'" で一括置換すればOK

以上です。

小ネタでしたが、どこかで誰かのお役に立てば幸いです :raised_hands:

カルテット開発部では、Symfonyを使いこなしたい仲間を募集しています!


このエントリーをはてなブックマークに追加

カルテット開発部の澤井です。

久しぶりのブログに、何を書こうかと色々と考えました。
悩んだ結果、やはり仕事で使う機会の多いSymfonyについて書こうと思います。

具体的には、Symfonyのイベントを使って、機能を拡張する簡単な例について書きます。

イベントについては、Built-in Symfony Events (Symfony Docs)に詳しい解説があります。

概要

本記事では、以下のような要望について考えます。

  • 通常のページでは、コントローラから返された連想配列を、Twigテンプレートを使って、HTMLのテーブルとして出力
  • 特定のページでは、コントローラから返された連想配列を、CSVファイルとしてダウンロード

本記事の目標は、イベントを使うことで、CSVファイルをダウンロードするという機能を一箇所で管理して、変更がしやすく、再利用性の高いコードを実現することです。

ちなみに、HTTPレスポンスヘッダに、以下の内容を指定することで、CSVファイルをダウンロードさせることができます。

  • Content-Typeヘッダに、text/csvを指定
  • Content-Dispositionヘッダに、attachmentを指定

コントローラの実装

まずは、@Templateアノテーションを使って、コントローラが返す連想配列を、テンプレートを使って表示します。

次章で、CSVファイルとしてダウンロードする機能を、イベントを使って実現します。

/**
 * @Route("/some")
 */
class SomeController extends Controller
{
    /**
     * @Route("/")
     * @Template
     */
    public function indexAction(Request $request)
    {
        // ...
        // $dataへ出力内容を保存する処理
        // ...

        return [ 'data' => $data ]
    }
    
    // ...

}

イベントの実装

CSVファイルをダウンロードする機能を、Symfonyのビルトインイベントであるkernel.viewイベントを使って実装します。

今回はサンプルなので、出力するデータは一次元配列かつカンマや改行などを含まないものとします。

namespace AppBundle\Listener;

// ...

class DownloadListener
{
    /**
     * @param FilterControllerEvent $event
     */
    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();
        if (!is_array($controller)) {
            return;
        }
        if ($controller[0] instanceof AssetController) {
            $event->getRequest()->attributes->set('is_download', true);
        }
    }

    /**
     * @param GetResponseForControllerResultEvent $event
     */
    public function onKernelView(GetResponseForControllerResultEvent $event)
    {
        if ($event->getRequest()->attributes->get('is_download')) {
            $controllerResult = $event->getControllerResult();
            $response         = new Response(
                implode(',', $controllerResult['data']),
                Response::HTTP_OK,
                [
                    'Content-Type' => 'text/csv',
                    'Content-Disposition' => 'attachment; filename=sample.csv',
                ]
            );
            $event->setResponse($response);
        }
    }
}

イベントを使うことで、CSVファイルをダウンロードする機能を、イベントリスナへ集約することができました。

その結果、他のページでCSVファイルをダウンロードする機能が必要になったときに、個別にコントローラへダウンロード機能を追加する必要はありません。

また、CSVファイルの文字コードを変換するといった、新たな要望が発生したときも、イベントリスナの修正だけで対応できます。

まとめ

今回は、イベントを使うことで、変更がしやすくて、再利用性の高いコードにすることができました。

Symfonyは、色々な場面でイベントを使います。 イベントに慣れて、上手に使うことが、Symfonyを使いこなすためのコツの1つかもしれません。

簡単な例でしたが、本記事でイベントの利点が伝われば嬉しいです。

以上、澤井でした。

カルテット開発部では、Symfonyを使いこなしたい仲間を募集しています!