PSR-17 HTTP Factories のライブラリ
Wednesday, May 01, 2019 08:15:00 PM
令和最初の記事も、PHP。 この記事はPSR-15リクエストハンドラーのライブラリ比較の続編です。
前回のサンプルプログラムでは zendframework/zend-diactoros の HTTP Message Factories を使って PSR-7のHTTPレスポンス(Psr\Http\Message\ResponseInterface
)を作っていました。
今回は、他のライブラリを使っても大丈夫か考えてみたいと思います。
PHP-17 の HTTP Factories に対応したライブラリ
PackagistでPSR-17を検索してみました。
PSR-15ほどはないようです。ということで独断と偏見(ダウンロード数が多いもの)を選んで比較してみたいと思います。
なお「フレームワーク」と書いてあるものや、特定のPSR-7ライブラリ だけ に依存したもの(たとえばhttp-factory-guzzle
など)は除外しています。
それぞれのライブラリの説明を読んで気づくでしょう。
PSR-17 HTTP-Factory with auto-discovery support
そう先ほど「特定のPSR-7ライブラリ だけ に依存したもの」と書きましたが、実は特定のライブラリに依存します。 それはそうですよね。PSR-7のHTTPレスポンスインターフェースの実装インスタンスを 生成 しないといけないので、何かしらに依存します。
ただ、こういった auto-discovery
してくれるライブラリを使っておくと、PSR-7のライブラリを変更したときも影響が少ないですね。
でもそれ、さっきのサンプルで DI してたから、それで良くない?というのは、まさにそのとおりです。
で、結局どうすると良いの?
- PSR-7/PSR-11/PSR-15/PSR-17 を使うアーキテクチャにするなら、FactoryInterfaceをDIすれば影響範囲は設定箇所だけになります
- PSR-7/PSR-15/PSR-17 を使う(PSR-11を使わない)アーキテクチャにするなら、上記のような PSR-7 を自動判定してくれるライブラリを使うと良い
ということになると思います。
それならPSR-7のライブラリも使い分けたサンプルが見たかった!とかあるかもしれませんが、それはまた今度!(機会があれば)
おまけ
さて、PSR-7/PSR-15/PSR-17 の話は面白かったですか? これに加えて、フロントエンドも含めてフレームワークに依存しないアプリケーションとは? みたいな話をPHPカンファレンス福岡2019でします。 午後一のセッション。また @soudai1025 の裏になりましたが、私の方がマニアックな話なのかな。
では6月に福岡でお会いしましょう!
PSR-15リクエストハンドラーのライブラリ比較
Tuesday, April 30, 2019 09:28:00 PM
平成最後の記事は、PHP。 久々のPHP記事ですが、PSR-15に準拠したリクエストハンドラーライブラリの実装を比較してみようと思います。
PSR-15とは?
HTTPメッセージを使用するリクエストハンドラーと、ミドルウェアコンポーネントの共通インターフェースです。
それPSR-7なのでは?という鋭い人は、 @tanakahisateruさんのスライド PHP-FIGのHTTP処理標準の設計はなぜPSR-7/15/17になったのかを参照ください。
PSR-7については、だいぶ知れ渡っていると思うので、PSR-15のリクエストハンドラーに着目していきます。
PHP-15のリクエストハンドラーに対応したライブラリ
PackagistでPSR-15を検索してみました。
たくさんありますね。ということで独断と偏見(ダウンロード数が多いもの)を選んで比較してみたいと思います。
なお「フレームワーク」と書いてあるものは除外しています。
例えば zend-expressiveは minimalist PSR-7 middleware framework for PHP
と書いてあるとおりなので。
Slimなどのマイクロフレームワークも同様です。
の4つを使ってサンプルプログラム集を作ってみました。
sizuhiko/psr15-requesthandler-examples
PSR-7
まず前提事項として、PSR-7対応のライブラリが必要です。 本サンプルでは、主に zendframework/zend-diactoros を使っています。 sunrise/http-routerの例ついては、同系統にsunrise/http-messageとsunrise-php/http-server-requestがあるので、それを利用しています。 PSR-7のライブラリが違うと、どのような記述の違いがあるのかわかりやすいでしょう。
サンプルの内容
サンプルプログラム集を clone
するか、ダウンロードして、READMEの手順に従ってください。
ドキュメントルート(/
)にアクセスすると、Hello, World!
出すだけの簡単なものです。
サンプルコードの流れ
で、結局PSR-15とは?みたいな話になるわけですが、どの例も以下のような流れで動いています
- PSR-7 でHTTPリクエスト(
Psr\Http\Message\RequestInterface
)を受け取る - PSR-15の
Psr\Http\Server\MiddlewareInterface
かPsr\Http\Server\RequestHandlerInterface
でいい感じに PSR-7のHTTPレスポンス(Psr\Http\Message\ResponseInterface
) を生成する。 - PSR-7 のHTTPレスポンスをエミットする
つまり、真ん中の部分を処理することになります。
リクエストハンドラ
サンプルのsrcフォルダの下には
- Middlewares
- RequestHandlers
があり、それぞれ Psr\Http\Server\MiddlewareInterface
か Psr\Http\Server\RequestHandlerInterface
を実装したクラスが置いてあります。
で、それぞれのリクエストハンドラーからは、適したハンドラが呼び出されるようになっています。
このサンプルでは PSR-17 (HTTP Factories) を先行導入し、PSR-11 (Container Interface) に対応したライブラリでDIしてますが、 そのあたりは、次回以降で解説します。
ミドルウエアもリクエストハンドラも同じようにHello, World!
をレスポンスボディに入れるだけです。
このサンプルをとおして言いたかったこと
このサンプルでは、ドキュメントルートだけの簡単な実装でしたが、ルーターの設定を追加するだけで、 実際のアプリケーションでも使えるようになることがわかると思います。
もちろん実際にはDBにアクセスする必要もあったりするわけですが、そこにはPHP Data Objects(PDO)があり、 実際のDBの差分を吸収してくれます。 そこで利用するSQLは標準であり、Webの標準よりも長い期間利用されています。
フレームワークを利用してアプリケーションを作ることは、速く簡単に構築できます。 しかしフレームワークに依存せずPHPの標準を使うことで、柔軟にライブラリを変えても、自分のビジネスロジックを流用することができるようになります。
もちろん今日のフレームワークの多くが PSR 対応を進めていますので、フレームワークを使っていても、より互換性が高いアプリケーションを作ることができるようになるかもしれません。
次回はPSR-17について、いくつかのライブラリを紹介します。
アスカン2019を開催しました
Monday, April 29, 2019 02:43:00 PM
明日の開発カンファレンス2019の中の人として運営参加しました。
私はプログラム枠1つを決めたり、事前準備をお手伝いしたり、当日雑用したりと、まぁ大したことはしてません(汗
私の渾身のオススメ枠、ということで今回は弊社岡島から「総売り上げ:35,400円 ~ 受託エンジニアが自社サービスのPOをやって学んだこと。」という発表をしてもらいました。 直前のセッションが、ヴェルク株式会社 田向 祐介さまの「受託開発の会社が自社サービスを立ち上げて軌道に乗せるまでの取り組み」だったこともあり、受託開発会社のサービス開発成功事例からの、失敗事例ということで、プログラムの流れも良かったと思います。
また今回のアスカンでは、はじめての2トラックということで、たくさんの事例をご紹介することができたと思います。
当日の様子は、Togetterにまとまっています。
明日の開発カンファレンス2019 - Togetter https://t.co/22BdcygB26 @togetter_jpさんから
— asuconjp (@asuconjp) 25 April 2019
@akiko_pusuさん、@NEKOGETさんが、グラレコを投稿してくれていますので、よりトーク内容含めてふりかえってもらえると思います。
昨年は秋にも開催したアスカンですが、今年はどうなるでしょうか?
そうそう、最後にアンケートもありますので、参加したみなさま、スピーカーやスタッフのためにも回答をお願いしたします。
明日の開発カンファレンス2019にご来場いただだきありがとうございました。スタッフ一同お礼申し上げます。 次回開催でもお会い出来ることを楽しみにしております。 より良いカンファレンスにするためアンケートを下記よりよろしくお願いします。https://t.co/snoRmEq6Aj #asucon #アスカンナイト
— asuconjp (@asuconjp) 25 April 2019
Toilet EvolutionのフロントエンドをPolymer3対応する(4)
Sunday, April 28, 2019 05:13:00 PM
この記事はToilet EvolutionのフロントエンドをPolymer3対応する(3)の続編です。
前回までの対応で、ページをロードしたときに、ブラウザのコンソールにエラーが出ることが少なくなりました。
ただし多くのページで表示が崩れていたり、うまく表示できないエレメントがあります。
これは今回の ES Modules
に対応してなかったエレメントに関連するところだったのですが、これらの対応を解説していきます。
dom-module has style outside template というワーニングが出る
ブラウザのコンソールを確認していると dom-module has style outside template
といったワーニングが表示されます。
これは <dom-module>
の中で <template>
と <style>
が並列に記述されている場合に発生します。
なので、すべて <template>
の子要素に <style>
を移動しました(コミット)。
動かすようにするための微調整
続いて1つずつの修正はそれぞれ大きくないものの、動作するまでの調整をたくさん実施しました(コミット)。
クリック処理が動かない
これは1から2の段階で廃止になった listeners
を使っていたためで、利用箇所を addEventListener
や、 on-tap
, on-click
に変更しました。
moment でロケールを利用しようとするとエラーになる
Toilet Evolution では、トイレの利用状況を表示するときに 10分前
のような表示をしているのですが、これに moment.js
の機能(toDate()
)を使っています。
moment
だけ(ロケールを使わない)なら npm でインストールして
import moment from 'moment';
と記述すればよかった(動いた)のですが、どうしてもロケールの解決がうまくいかない(Webpackするとエラーになる)ので、今回はあきらめてHTML側でグローバルに利用できる形にしました。
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/locale/ja.js"></script>
いくつかWebpackとmomentのissueも見つけて解決策もありそうだったのですが、とりあえず困らないのでこの方法で。
style や slot が解決されない
modulizerで自動変換された <google-map-marker>
エレメントは以下のようになっていました。
const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="google-map-marker">
<style>
:host {
display: none;
}
</style>
<template><slot></slot></template>
</dom-module>`;
document.head.appendChild($_documentContainer.content);
もとのHTMLでの記述は以下のようになっていました。
<dom-module id="google-map-marker">
<template>
<style>
:host {
display: none;
}
</style>
<slot></slot>
</template>
<script>
自分が作ったカスタムエレメントでは、 Polymer
の _template
に html
を使うように変換されていたのですが、bowerでインストールしたコンポーネントの多くは上記のように変換されていました。これを html
を使うようにしてみたところ解決しました。
Polymer({
_template: html`
<style>
:host {
display: none;
}
</style>
<slot></slot>
`,
<google-map>
エレメントも同様にうまく動作しなかったので、 html
をつけて _template
で返却するように対応しました。
さいごに
4回にわたって、Polymer1のプロジェクトをPolymer3に移行した解説をしてきました。 この連載がPolymer1からアップグレードする他の方の手助けになれば幸いです。
基本的な部分は、ほとんどmodulizerで変換できるので、これは便利だなーと思うのでした。 Polymer3対応した依存エレメントは、どこかのタイミングでPRを出してフィードバックしたいなと思っています。
では良いWeb Componentsライフを!
Toilet EvolutionのフロントエンドをPolymer3対応する(3)
Saturday, April 27, 2019 07:16:00 PM
この記事はToilet EvolutionのフロントエンドをPolymer3対応する(2)の続編です。
今回もmozlier適用だけでは動かないので、ローカルで動作するように修正というコミットにおける試行錯誤を書いていきます。
前回は多くのアプリケーションや、カスタムエレメントで実施しなければならない共通的な修正箇所について解説しましたが、ここからはアプリケーションで使っている機能やエレメントについて、修正が必要だった箇所について解説していきます。
ES Module対応になっていないエレメントを使う
前回の記事で「bower_components を使わないようにする
」について解説しました。
PolymerチームやVaadinチームなどが作っているコンポーネントについては、ほとんど ES Module
に対応しているのですが、場合によっては対応してないモジュールを使っていることがあるかもしれません。
Toilet Evolutionでは以下のエレメントが ES Module
に対応していませんでした。iron-signals
は toast-er
の依存に関連しています。
そこで、これらのエレメントは modulizer で変換されたものを、そのまま利用することにしました。
また変換されたエレメントについては、前回の記事同様に共通的な修正箇所が必要になります。
つまり自分で作ったエレメントと同様に、そのエレメントが依存している(bower.jsonに含まれている)エレメントやライブラリについても、 npm install
で取得するように変更する必要があります。
またPolymer1用のライブラリだったりする場合は、Polymer1から2へのアップグレードガイドに書いてある slot
の対応なども必要だったので、そのライブラリが最新版だとPolymerのどのバージョンに対応したものなのかを確認しておくことが重要です。
そして、これらの作業が結構やっかいです(自分で作ったものでないので、ソースを理解する必要があります)。
以前のPolymerのビヘイビアは個別にインストールする必要がある
HTMLインポートで利用していた、Polymerチームが作っていたようなカスタムエレメントのビヘイビアは、個別に import
するか、場合によっては npm install
で導入する必要があります。
自分で作ったエレメントでは、ビヘイビアを使っていなかったので、この段階で初めて知りました(これは意外にもドキュメントに書いていません)。
例えば <gold-password-input>
では、PaperInputAddonBehavior
という paper-input
に含まれていたビヘイビアを使っています。
これは以下のように、import
を追加してあげる必要があります。
import {PaperInputAddonBehavior} from '@polymer/paper-input/paper-input-addon-behavior.js';
ES Module
対応しているエレメントであれば、webcomponents.orgのビヘイビアを参照すると解説が書いてあります。
上記の PaperInputAddonBehavior
であれば、こちらです。
Polymer.dom を変更する
これも自分のエレメントでは使っていなかったので気付かなかったのですが、使っているエレメントがあったので修正の必要がありました。
まず dom
をインポートします。
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js'
で、Polymer.dom
を使っている箇所を dom
に変更します。例えば以下のような感じです。
return dom(this).parentNode;
bowerでカスタムエレメント以外のライブラリに依存している
<gold-password-input>
はzxcvbnというパスワードストレングスエミュレータを使っています。
Node.jsなどにも対応しているのですが、今回はbowerでインストールしたフォルダをそのままコピーして、リポジトリに追加しました。
このようにカスタムエレメント以外のライブラリを使っている場合は、npmでインストールしてビルドする方法以外の検討も必要となります。
特に<gold-password-input>
では、以下のように script
タグを動的に追加してライブラリをインポートしていたため、npmを利用するのに適していなかったという理由があります。
ready: function() {
isZxcvbnLoaded = typeof zxcvbn !== "undefined";
if (!isZxcvbnLoaded) {
isZxcvbnLoaded = true;
var oScript = document.createElement("script");
oScript.type = "text\/javascript";
oScript.onerror = function(err) {
isZxcvbnLoaded = false;
throw new URIError("The script " + err.target.src + " is not accessible.");
};
this.parentNode.insertBefore(oScript, this);
oScript.src = this.resolveUrl("../zxcvbn/dist/zxcvbn.js");
}
},
このぐらいまで対応が進むと、ページをロードしたときに、ブラウザのコンソールにエラーが出ることが少なくなります。
ただし多くのページで表示が崩れていたり、うまく表示できないエレメントがあります。
これは今回の ES Modules
に対応してなかったエレメントに関連するところなのですが、
これらの対応方法については次回解説していきます。
Recent Articles
- GAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記 〜 その 2 2024/03/20
- GAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記 〜 その 1 2024/03/20
- マルチプルレポをモノレポへコミットログを残しながら移行する 2023/09/27
- tsyringe を TypeScript 5 で使う方法 2023/05/02
- LocalStack を使って aws-sdk の Integration Test を実行する 2023/04/19
- AWS SDK v3 のモジュールと利用方法 2023/04/18
- ts-jest が esbuild/swc をトランスフォーマーに使って高速化していた 2023/04/13
- aws-sdk v3 を使うライブラリを作ったときは、なるべく peerDependencies に設定しよう 2023/04/11
- aws-sdk v2 が 2023 年中にメンテナンスモードになる 2023/04/06
- Node.js v18 / aws-sdk v3 の Lambda アプリが突然動かなくなる 2023/04/05