20200519のPHPに関する記事は17件です。

しいたけ少年のはじめに

今日の学び

今日はPHPの正規表現につかえるWebサイトを見つけました。
PHP Live Regex
同様のページはたくさんありますが、ものによって結果が違ったりするんですよね。
見やすくて(自分の望んだ結果が出てきてくれたので)今後はこれを採用します。おめでとう!
というかそもそも正規表現あんまりわからん。

以下はどうでもいい情報なので仕事や勉強に疲れて気でもおかしくなった際に読んでください。

自己紹介

2020年4月からWeb系の会社でコードを書くお仕事をしている20代青春真っ盛りの少年です。

プログラミングの経験は大学生の頃に
「プログラミングってなんかかっこいい〜!」と思って少し触った程度です。
その頃はCやPythonなど触ってましたが、

nanigatanoshiinkore.c
printf("なにが楽しいんこれ?");

となってしまったおかげでろくな知識も得られぬまま大学生活が終わりました。

目的

未経験で入社したため学びの多い日々を過ごしていますが、
吸収するばかりで脳みそが膨張して爆発しそうなので
こういった場所で学んだことを記録して少しでも自分の脳みそに安らぎを与えたいと思いQiitaってみます。

使用言語

主にPHPを使用しています。
HTML, CSS, JavaScriptもたまーに触りますが、ほとんど分かりません。助けて。

おわりに

これから脳みそがパンクしそうなときには更新していきたいです。
これまでに始めたブログ3個、内半年もしないまま終わったブログ3個。
続けばいいなあ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】 プロセスが永遠に起動している問題への対策と知見

はじめに

「いい感じにTIMEOUTしてくれるだろう普通。」と思っていたら痛い目に合いました。

PHPで、とある監視プロセスをcron的に繰り返し実行しているときに、ログからプロセスが全くkillされないことに気づいた。
※そのプロセスの内部では、CURLコマンドを使って外の情報を取得してきている。

どうしてだろうと調べているときに、下記を上司に教えていただき頭の整理がつきました。
上司かつ以下のリンク著者に感謝です。

https://ngyuki.hatenablog.com/entry/2019/09/21/191552

内容

結論

「CURLOPT_TIMEOUT」を設定していない状況で、端末へ映像などの情報を取得しに行く際に取得できなかったとき、無制限に待たされるとのこと。

詳細

CURLOPT_TIMEOUT
これは、端末へ接続にでき、映像などの情報を取得しに行くときに設定するTIMEOUTになります。
例)
「端末に接続で来たけど情報取得で待たされる。」
というときに、どれくらいでTIMEOUTするのかを設定する項目となっています。

ちなみに、「CURLOPT_CONNECTTIMEOUT」も適切に設定しなければ、端末への接続時に失敗したときに、デフォルト値が参照されたり設定されたものが適応されるので注意が必要です。

CURLOPT_CONNECTTIMEOUT
これは、端末へ接続しに行くときに設定するTIMEOUTになります。
例)
「端末に接続しに行こうとしたけど、待たされる。」
というときに、どれくらいでTIMEOUTするのかを設定する項目となっています。

以下参考

https://ja.coder.work/so/php/143295

さらに、以下も注意しておきたいところです。

CURLOPT_CONNECTTIMEOUTはCURLOPT_TIMEOUTで表される時間のセグメントであるため、
CURLOPT_TIMEOUTの値はCURLOPT_CONNECTTIMEOUTの値より大きくする必要があります。

また、デフォルト値がどういう設定になっているかなどは以下を参考。

https://www.it-swarm.dev/ja/php/php%EF%BC%9A%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AEcurl%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%A2%E3%82%A6%E3%83%88%E5%80%A4/1067580731/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

$.getメソッドを使って非同期通信でapiを表示する

Ajaxでapiを表示する

動的なページで自作したapiを静的なフロントのページで表示させる必要があったので備忘録として残します。

laravelでapiの作り方

動的なページ側での話。
Http/Controllers/APIにapi用のコントローラーを作成。
今回はFAQのAPIを作る。

FAQAPIController
class APIFAQController extends Controller
{
    public function index(Request $request){
        $faq = Faq::all();
        header("Access-Control-Allow-Origin: *");
        return Response::json($faq);
    }
}

routeのapi.phpにapi用のルートを設定する

//FAQ API
Route::get('/index','API\APIFAQController@index')->name('api.index');

これでURLに api/index にアクセスするとjsonでレスポンスが返ってくる
postmanで確認するとapiの中身が確認できる。

apiの受け取った通信データの表示方法

ここから静的ページサイトでどうやって表示させるかという話。
$.getメソッドを使って通信データを取得できる
$.get('apiのurl',function(data))
functionの中のdataが引数で通信データを受け取ることができる。

index.html
 $.get('apiurl',function(data){
   //処理を書く
 })

あとは処理を書いていけばよい

index.html
<script>
  $(function(){
        $.get('https://faq.com/api/index', function(data){
            for(var i=0; i<data.length; i++){
                var question = data[i].question;
                var answer = data[i].answer;
                console.log(question);
                console.log(answer);
            }
</script>

こんな感じです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[CakePHP 3.x] migration,seed command

Technical requirement

  • CakePHP 3.5

Official reference

CakePHP Cookbook 3.x - Migrations

Command

Migration

bin/cake migrations migrate

Migration rollback

bin/cake migrations rollback

Migration create

bin/cake migrations create MyCustomMigration

Seed

bin/cake migrations seed

Seed --seed

Specify only one seeder.

bin/cake migrations seed --seed [seeding class name]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

学習記録PHP#2(テキストファイル操作の基本)

PHPにおけるテキストファイル操作の基本

テキストファイルの情報を複数人で共有する場合。

テキストファイルへのデータの書き込み

ファイルオープン

$fp = fopen(実際に開くパス, 'wb');

fopen:戻り値を返す関数
ファイルポインタ(ここでは$fp):ファイル情報を管理するもの
wb:上書きモード

ファイルに書き込む

fwrite($fp, 書き込むファイル);

ファイルクローズ

fclose($fp);

テキストファイルからのデータの読み込み

$fp = fopen($filePath, 'rb');

rb:ファイルを読み込むモード
ab:追記モード

ロックをかける

flock($fp, LOCK_EX); 排他ロック
flock($fp, LOCK_SH); 共有ロック

ファイルを読み込む

$value = fgets($fp);

ロックの解除

flock($fp, LOCK_UN);

ファイルクローズ

fclose($fp);

ロックの基本的な考え方

ロック:ファイルなどの読み書きに関するユーザーごとの権限制御。(1つのファイルやデータベースを複数ユーザーで共有して書き込みを行う場合、ユーザーごとに読み書きの制限をしないと問題が生じる。)

3種類のロック(ロックなし、共有ロック、排他ロック)

ロックなし

読み書きの両方が可能。
ファイルを読み込みモードで開くと、標準ではロックなしとなる。他の人は同じファイルに対し、読み書きの両方を実行可能。

共有ロック

読み込みは可能。書き込みは不可。
ファイルを書き込みモードで開くと、標準は共有ロックとなる。他の人は同じファイルに対し読み込みのみ実行可能。

排他ロック

読み書き共に不可。
ファイルを開く際、明示的に排他ロックの指定を行うことで設定可能。排他ロックで開かれたファイルは他の人は読み書き不可。

ロックの具体的な使い方

fopen関数、wbモードで開くと共有ロックがかかる。ファイルを閉じるとロックは自動的に解除される。
fopen関数、rbモードで開くとロックはかからない。自分で排他ロック等をかけることはできる。
排他ロック等をかけた場合もファイルクローズを行うと自動的にロックは解除される。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

学習記録PHP#2(テキストファイル操作の基本、アップロードファイルの管理)

PHPにおけるテキストファイル操作の基本

テキストファイルの情報を複数人で共有する場合。

テキストファイルへのデータの書き込み

ファイルオープン

$fp = fopen(実際に開くパス, 'wb');

fopen:戻り値を返す関数
ファイルポインタ(ここでは$fp):ファイル情報を管理するもの
wb:上書きモード

ファイルに書き込む

fwrite($fp, 書き込むファイル);

ファイルクローズ

fclose($fp);

テキストファイルからのデータの読み込み

$fp = fopen($filePath, 'rb');

rb:ファイルを読み込むモード
ab:追記モード

ロックをかける

flock($fp, LOCK_EX); 排他ロック
flock($fp, LOCK_SH); 共有ロック

ファイルを読み込む

$value = fgets($fp);

ロックの解除

flock($fp, LOCK_UN);

ファイルクローズ

fclose($fp);

ロックの基本的な考え方

ロック:ファイルなどの読み書きに関するユーザーごとの権限制御。(1つのファイルやデータベースを複数ユーザーで共有して書き込みを行う場合、ユーザーごとに読み書きの制限をしないと問題が生じる。)

3種類のロック(ロックなし、共有ロック、排他ロック)

ロックなし

読み書きの両方が可能。
ファイルを読み込みモードで開くと、標準ではロックなしとなる。他の人は同じファイルに対し、読み書きの両方を実行可能。

共有ロック

読み込みは可能。書き込みは不可。
ファイルを書き込みモードで開くと、標準は共有ロックとなる。他の人は同じファイルに対し読み込みのみ実行可能。

排他ロック

読み書き共に不可。
ファイルを開く際、明示的に排他ロックの指定を行うことで設定可能。排他ロックで開かれたファイルは他の人は読み書き不可。

ロックの具体的な使い方

fopen関数、wbモードで開くと共有ロックがかかる。ファイルを閉じるとロックは自動的に解除される。
fopen関数、rbモードで開くとロックはかからない。自分で排他ロック等をかけることはできる。
排他ロック等をかけた場合もファイルクローズを行うと自動的にロックは解除される。

PHPでのアップロードファイルの管理

スーパーグローバル変数「$_FILES」

アップロードされたファイルを受け取る際に使用する。

ファイル名:$upfileName = $_FILES['upfile']['name'];
テンポラリファイル:$upfileTmp = $_FILES['upfile']['temp_name'];
(テンポラリファイル:サーバー上に保存されたファイル)
ファイルサイズ:$upfileSize = $_FILES['upfile']['size'];
ファイルタイプ:$upfileType = $_FILES['upfile']['type'];
エラー情報:$upfileError = $_FILES['upfile']['error'];

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC-CUBE4系でのプラグインエラーの原因と対処法

この記事は、 EC-CUBE4系でプラグインインストール時にエラーが出た時の対処法 の詳細版です。

EC-CUBE4系では、 フレームワークとして Symfony3.4 が採用され、プラグインの管理に Composer が利用されるようになりました。
モダンな技術を取り入れた反面、動作させるために多くのリソースを消費するようになりました。

特に、プラグインのインストール/有効化/無効化/アンインストール時には、以下のような処理が実行されるため、大量のリソースを消費します。

  • Composer での依存関係解決
  • Composer の classmap 生成
  • Symfony DependencyInjection コンテナのコンパイル(キャッシュ生成)
  • Doctrine ORM のキャッシュ生成
  • Entity Proxy 生成

これらフレームワークのキャッシュを活用することで、運用時のパフォーマンス向上を実現しています。
現代のフレームワークは、キャッシュに支えられているといっても過言ではありません。
しかし、大量の細かいファイルを生成し読み込むために、 Windows 環境や Docker との相性を悪くしている原因にもなっています。

プラグインインストール時に発生するトラブルの大半が、これらキャッシュファイルの処理が失敗することによって発生します。
端的に言うと、キャッシュファイルの運用を安定化させれば、プラグインインストール時のトラブルを無くすことが可能です。

確実にプラグインインストールを成功させるためには

詳細は後述しますので、手っ取り早く解決したい方は本項のみを読んでください

プラグインインストール時のトラブルの大半は、フレームワークのキャッシュ生成に失敗することで発生しますので、以下の2点をクリアすれば防止することが可能です。

  1. 性能の良いサーバーを使用する
  2. メンテナンス画面にして、外部からのリクエストを遮断する

プラグインの不具合や競合で失敗する場合は、プラグインや本体を修正するしかありません...

性能の良いサーバーを使用する

クラウドや VPS など、潤沢なリソースのサーバーを選択することが重要です。
経験値としては、6コア/メモリ8GB 以上あれば比較的安定しています。
クラウドの場合は、プラグインインストール/有効化/無効化/アンインストール時にスケールアップすると良いと思います。(オートスケールはトラブルの原因になるためおすすめしません)

レンタルサーバーでの利用は、かなり厳しい状況なのですが、、、 さくらのレンタルサーバーは例外です。安価なスタンダードプランでも大丈夫です。
その理由は、 FreeBSD という Linux とは別物の OS を利用しているためです。

プラグインをインストールする際、大量のリソースを消費します。
性能の低い Linux サーバーですと、サーバーダウンの危険があるため OOM Killer という OS 保護機構が働いて、プラグインインストールのプロセスを強制終了させてしまいます。
これがプラグインインストールトラブルの多くの原因になっているのですが、 FreeBSD には、この OOM Killer がありません。
OOM Killer によって、プラグインインストールのプロセスが強制終了されることは無いために、安価なスタンダードプランでも安定してインストールできます。

性能の高いサーバーや、 FreeBSD でもシステムエラーになるケースがあるのですが、次項のメンテナンス画面を併用することで、ほぼ解消できると思います。

メンテナンス画面にして、外部からのリクエストを遮断する

無事にプラグインのインストールが成功しても、有効化時にシステムエラーになる場合があります。
プラグインの有効化をする際、各種キャッシュファイルを生成し直すのですが、このときに外部からのアクセスがあると、複数のプロセスでキャッシュファイル生成が競合してしまう場合があり、システムエラーの原因になります。
これは、メンテナンス画面にして、外部からのリクエストを遮断することで解消できます。

EC-CUBE4.0.1以降では、 EC-CUBE をインストールしたフォルダ直下に .maintenance というファイル名のファイル(中身は何でも良い)を置くと、メンテナンス画面になります。

具体的な手順は、以下の通りです。

  1. <EC-CUBEインストールフォルダ>/.maintenance ファイルを設置する
  2. フロント画面がメンテナンス画面になったのを確認する
  3. プラグインインストール/有効化/無効化/アンインストールを実行する(コマンドラインから実行すると、より安定します。 )
  4. 管理画面を何度かリロードして、システムエラーにならないのを確認する
  5. <EC-CUBEインストールフォルダ>/.maintenance ファイルを削除する
  6. フロント画面が正常に表示されるのを確認する

4 でシステムエラーになった場合は、プラグインの不具合や、競合の可能性があります。
プラグインや本体を修正する必要がありますので、 var/log 以下にあるログのシステムエラーと表示されている行をご確認ください。

コマンドラインでのプラグインインストール

管理画面からのWebインストーラよりも、コマンドライン操作の方が格段に安定しています。
何度やってもWebインストールに失敗してしまう場合、コマンドライン操作に慣れている方はお試しください。

オーナーズストアプラグイン、独自プラグインでコマンドが異なりますのでご注意ください。
事前にメンテナンス画面に変更しておくことを忘れずに。
キャッシュ削除/キャッシュ生成もコマンドラインで実行するのがポイントです。

## 事前準備 - メンテナンス画面に変更
touch .maintenance

## オーナーズストアプラグインインストール
bin/console eccube:composer:require ec-cube/<PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## 独自プラグインインストール
bin/console eccube:plugin:install --code <PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## プラグイン有効化
bin/console eccube:plugin:enable --code <PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## プラグイン無効化
bin/console eccube:plugin:disable --code <PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## オーナーズストアプラグインアンインストール
bin/console eccube:composer:remove ec-cube/<PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## 独自プラグインアンインストール
bin/console eccube:plugin:uninstall --code <PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## オーナーズストアプラグインアップデート
bin/console eccube:composer:update ec-cube/<PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## 独自プラグインアップデート
bin/console eccube:plugin:update <PluginCode>
bin/console cache:clear --no-warmup # キャッシュ削除
bin/console cache:warmup # キャッシュ生成

## メンテナンス画面を解除
rm .maintenance

プラグインエラーの原因と対処法詳細

Composer での依存関係解決時のエラー

EC-CUBE4系では、 Composer を利用して、プラグインの依存関係を制御しています。
EC-CUBE に限らず Laravel で開発したプロジェクトなど、 Composer を使用するプロジェクトすべてにあてはまるのですが、 composer require コマンドを実行する際に400MB〜600MBのメモリを消費します。
これは、Composer の依存関係にある JSON ファイルをすべてメモリ上に読み込むためです。

通常、 Composer の操作はコマンドラインで実行するため、問題になることは少ないのですが、 EC-CUBEの場合は Webインターフェイスを使用するために問題になります。

1リクエストで400MB〜600MBのメモリを消費するWebアプリケーションというのは明らかに異常な状態です。
(通常は多くても数十MB)
CPUの利用率も高い状況が継続するため、Linux では OOM Killer という OS 保護機構が働いて、プラグインインストールのプロセスを強制終了させてしまいます。

このケースでは、エラーログが出力されない場合があり、原因の特定を困難にさせる一因となっています。

対処方法

OOM Killer は Linux 固有の機構ですので、さくらのレンタルサーバーで採用されている FreeBSD など、 Linux 以外の OS では影響を受けません。
また、クラウドや VPS などで性能の良いインスタンスを使用することで、 OOM Killer の影響を低減させることが可能です。

管理画面から実行するよりも、コマンドラインから実行した方がより安定します。

よく、 php.ini の memory_limit を増やしましょうという対処法を紹介しているブログなどがあるのですが、このケースの場合は殆ど意味がありません。
Composer は、内部的に memory_limit を 1.5GB まで自動的に増加させるためです。
(つまり、メモリ 1.5GB 未満のミニマムな環境では危険な状態になります)

Docker を使用する場合は --oom-kill-disable というオプションがありますので、試してみると良いでしょう。

まとめると、以下の2点の対応で解消できる可能性が高いです。

  • 性能の良い環境を使用する or Linux 以外の OS を使用する
  • コマンドラインから実行する

後程詳細を追記します...

  • Composer の classmap 生成時のエラー
  • Symfony DependencyInjection コンテナのコンパイル時のエラー
  • Doctrine ORM のキャッシュ生成時のエラー
  • Entity Proxy 生成時のエラー
  • max_execution_time タイムアウト
  • FastCGI のタイムアウト
  • ブラウザのタイムアウト
  • レンサバのプロセス実行タイムアウト
  • プラグインの競合、不具合
  • インストール中の DBエラーによるロールバック
  • リソース(メモリ、CPU)不足

どうしても解決できないときは

この投稿のコメント覧でお問い合わせください

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WEB DB ExmentをWin10にインストールしてみる

Exmentとは

ブラウザでデータベースの構築・入力ができるWebDB
公式サイト:https://exment.net/
デモサイト:https://exment.net/demo-env
alt

類似ソフト

・[有償]UnitBase,kintone,XCGate,i-repoter
・[無償版あり]Pleasanter

特徴

・オープンソース 無料でアカウント数無制限
・Apache+PHPで動くのでXamppやレンタルサーバーで稼働できる
・データベースはPC、タブレット、スマホから入力・閲覧できる
・ワークフロー機能あり
・APIあり

インストールしようと思った理由

・会社でペーパーレス化導入で数社から説明・見積もりを取った。
・UnitBaseが面白いと思ったが採用されず、試用期間が切れた。
・ExmentがUnitBaseと同じようなWebDBでオープンソースで無償で使えるようなので使って試してみることにした。

インストール

環境

・OS:Windows10

説明

公式インストール説明:https://exment.net/docs/#/ja/quickstart

ダウンロード

以下をダウンロードする

composer

以下のサイトに説明があるのでダウンロードして実行ファイルを実行する
https://weblabo.oscasierra.net/php-composer-windows-install/

Xampp

最新版はPHPのバージョンが新しすぎて動かないので「7.3.17 / PHP 7.3.17」版をダウンロードしてセットアップする。
https://www.apachefriends.org/jp/download.html
以下にセットアップ手順が記載してある。MySQLの環境変数パスは「C:\xampp\mysql\bin」
https://exment.net/docs/#/ja/install_xampp

Exment

https://exment.net/downloads/ja/exment.zip
ダウンロードして解凍し「C:\xampp\local\exment」へコピーする

データベース設定

以下を開き、「新規作成」で「homestead」データベースを作成する
http://localhost/phpmyadmin/index.php

httpd-vhosts.conf,hosts修正

以下をみて「httpd-vhosts.conf」,「hosts」を修正する。
https://exment.net/docs/#/ja/install_xampp?id=%e3%82%b5%e3%83%96%e3%83%89%e3%83%a1%e3%82%a4%e3%83%b3%e8%a8%ad%e5%ae%9a

インストール

以下を開く
http://exment.localhost/admin
データベース設定は以下を設定する。
データベース種類:MariaDB
ホスト名:127.0.0.1
ポート:3306
データベース:homestead
ユーザー名:root
パスワード:(空欄)

感想

・思ったより簡単に動いた
・データベースの入力の仕方に悩んだ。「管理者設定」-「メニュー」-「新規」で作成したデータベースを追加すると入力できるようになる。
・ワークフロー機能に期待。Excel,Accessには無い機能だから。
・ワークフローはほとんど状態遷移なので色々使えそう。
・クロス集計ビューが欲しい。横軸が日付だと助かる。
・APIをPythonから動かすことに挑戦してみたい。
キャプチャ.PNG

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WEBデータベース ExmentをWin10にインストールしてみる

Exmentとは

ブラウザでデータベースの構築・入力ができるWEBデータベース(WebDB)
ExcelやAccessでやっている作業を、ACCESSを操作する感じでWEBデータベースで作ることができる。
公式サイト:https://exment.net/
デモサイト:https://exment.net/demo-env
alt

WEBデータベース(WEB DB)とは

データベースをブラウザで見たり入力したりすることができ、テーブルの定義もブラウザでできる。ノンプログラミングでデータベースを開発・運用できることが特徴です。

以下、公式のデモサイトです。実際に見てみるのが早いかと。

基本的なデモ環境です。
管理者権限を付与しております。
URL: https://demo-jp.exment.net/admin
ログインID : admin
パスワード: adminadmin

類似ソフト

・[有償]UnitBase,kintone,XCGate,i-repoter
・[無償版あり]Pleasanter

特徴

・オープンソース 無料でアカウント数無制限
・Apache+PHP+MySQLで動くのでXamppやレンタルサーバーで稼働できる
・データベースはPC、タブレット、スマホから入力・閲覧できる
・ワークフロー機能あり
・APIあり

インストールしようと思った理由

・会社でペーパーレス化導入のため数社から説明・見積もりを取った。
・UnitBaseが面白いと思ったが採用されず別なシステムが導入され、UnitBaseの試用期間が切れた。
・Apache+MySQL+PythonでCGIで何か書こうと思った時、WEB DBの事を思い出して「WebDB フリー」で検索してみた。
・ExmentがUnitBaseと同じようなWebデータベースで、オープンソースなので無償で使えるようなので試してみることにした。(Pleasanterも30日無料トライアル試してみたけど複雑そうと思った)

インストール

環境

・OS:Windows10

説明

公式インストール説明:https://exment.net/docs/#/ja/quickstart

ダウンロード

以下をダウンロードする

composer

以下のサイトに説明があるのでダウンロードして実行ファイルを実行する
https://weblabo.oscasierra.net/php-composer-windows-install/

Xampp

最新版はPHPのバージョンが新しすぎて動かないので「7.3.17 / PHP 7.3.17」版をダウンロードしてセットアップする。
https://www.apachefriends.org/jp/download.html
以下にセットアップ手順が記載してある。MySQLの環境変数パスは「C:\xampp\mysql\bin」
https://exment.net/docs/#/ja/install_xampp

Exment

https://exment.net/downloads/ja/exment.zip
ダウンロードして解凍し「C:\xampp\local\exment」へコピーする

データベース設定

以下を開き、「新規作成」で「homestead」データベースを作成する
http://localhost/phpmyadmin/index.php

httpd-vhosts.conf,hosts修正

以下をみて「httpd-vhosts.conf」,「hosts」を修正する。
https://exment.net/docs/#/ja/install_xampp?id=%e3%82%b5%e3%83%96%e3%83%89%e3%83%a1%e3%82%a4%e3%83%b3%e8%a8%ad%e5%ae%9a

インストール

以下を開く
http://exment.localhost/admin
データベース設定は以下を設定する。
データベース種類:MariaDB
ホスト名:127.0.0.1
ポート:3306
データベース:homestead
ユーザー名:root
パスワード:(空欄)

感想

・思ったより簡単に動いた
・データベースの入力の仕方に悩んだ。「管理者設定」-「メニュー」-「新規」で作成したデータベースを追加すると入力できるようになる。
・ワークフロー機能に期待。Excel,Accessには無い機能だから。
・ワークフローはほとんど状態遷移(ステートマシン)なので色々使えそう。
・最初にUnitBaseでWEBデータベースを見た時、「これとワークフロー組み合わせたら業務のプログラミングができそう」と思った。
キャプチャ.PNG
・スマホからも開けるので、パソコン無くても入力できる。
Screenshot_20200519-122150.png

要望

・クロス集計ビューが欲しい。横軸が日付だと助かる。縦軸が作業者・横軸が日付(一か月)で静電防止対策のチェックをつけている表を作ってみようとしてクロス集計が欲しいと思った。
・スマホで見ているときに、フォームにスマホのカメラをバーコードリーダーにして入力できると、ロケーションフリーで使えるので用途が広がる。

やってみたいこと

・課と課をまたぐ業務のワークフロー化
 課と課をまたぐ作業の帳票をワークフロー化することでメールベースの事故を防ぐ
 全社的なワークフローはあるが、さすがに部内の仕事に導入するには小回りが利かない。
 製造→技術→品証→資材を経由する出荷データ確認用ワークフローを試しに作ってみた。
キャプチャ.PNG

・APIをPythonから動かすことに挑戦してみたい。元々組み込み屋(エンベデッドプログラマ)なので、Iotデバイス(RaspberryPIなど)からDBにデータを登録したい。

WEBデータベースの使えそうな所

・台帳管理 採番台帳にはもってこい
・ワークフロー 状態遷移図でかけるくらいのもの。データは添付ファイルで渡してもよい
・タスク管理 ワークフローの応用
テーブル1つで書けるものをお勧めする
・Iotのデータ収集 ネットワーク対応のAPIに期待

WEBデータベースの苦手そうな所

・複数のテーブル、複雑なロジックが必要なもの
 データベースは元々プログラムとデータを分離してデータだけ共用できるようにしたもの。
 使うためにはロジック部のプログラムが必要。ノンプログラミングの分そのあたりは弱くなる。APIを使って外部にプログラムを作ることが必要になる。
 一見簡単に見える帳票でも複雑な構造をしていることがある。
 一例で他部所でペーパーレス化を試みた帳票を私が解析したものが以下になる。
 最低でも7テーブル必要なものを1つのテーブルに突っ込もうとしていたので、お話にならないと思った。
キャプチャ.PNG

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPとJavaScriptの違いまとめ(主要項目の対比表)

PHPとJavaScriptの違いまとめ(主要項目の対比表)

PHPとJacaScriptのメソッドなど主要項目の違いまとめ。
どっちがどっちかわからくなるの防止。

「←」はPHPの記述と同じ。


項目 PHP JavaScript
変数 *1 $変数名 var/let/const 変数名
関数 function 関数名(){} function 関数名(){};
アロー関数 *2 fn()=>処理 ()=>{};
引数 $仮引数名 仮引数名
処理の終わり ;
コメントアウト // or /* */
クラス定義 class クラス名{}
コンストラクタ アクセス権 function __construct(){} constructor(){}
インスタンス new クラス名()
プロパティ アクセス権 $プロパティ名 const オブジェクト名 = {プロパティ名:値}
プロパティの呼び出し インスタンス->プロパティ名 オブジェクト.プロパティ名
プロパティに関数をセット なし {プロパティ名:()=>{処理}};
メソッド アクセス権 function メソッド名() メソッド名(){}
インスタンス自身(メソッドのみ) $this this
自身のプロパティ呼び出し $this->プロパティ名 this.プロパティ名
メソッド呼び出し インスタンス->メソッド名() インスタンス.メソッド名()
継承 class クラス名 extends 親クラス名{}
クラスの使用許可 不要 export default クラス名
クラス読込み require_once('ファイル名.拡張子') import クラス名 from "./ファイル名"
コンストラクタのオーバーライド *3 parent::__construct(); super()
出力 echo/print console.log()
配列の要素数 count(配列) 配列.length
配列 array() []
キーあり配列 array(キー名=>値) {キー名:値}
キーあり配列の値取得 *4 配列[キー名] 配列.キー名
キーあり配列呼び名 連想配列 オブジェクト
for文 for($変数=初期値: 条件式: ステップ){}
配列からひとつずつ抜き出す foreach($変数名 as 配列) 配列.forEach((変数名)=> {処理});
if文 if(条件式){}
else if elseif (条件式){} else if (条件式){}
switch文 switch(){case 条件: 処理; break;,,, default:}
変数展開 *5 "${変数}" `${変数}`
and &&/and
or パイプ2本/or
等しい == ===/==
異なる != !==/!=
インクリメント演算子 ++
デクリメント演算子 --
整数型に変換 intval() perseInt()/Number()
文字列型に変換*6 strval() String()/ .toString() / +''
小数点に型変換 floatval() parseFloat()
3桁区切り number_format() 数値.toLocaleString()

*1. let:再宣言NG、const:定数(再宣言・再代入NG)
*2. PHP:アロー関数は1行のみ。
  JS:複数行OK。代入した変数が関数名になる(phpも)。
*3. JS:super()の引数は親クラスのコンストラクタの引数と合わせる
*4. JS:プロパティと呼ぶ
*5. PHP:シングルクオテーションだと文字列として出力
  JS:バッククオート(shift+@)
*6. JS:空の文字列を足すと自動で文字列型に変換

JSはES6からクラスが使えるようになった。PHPと同じ処理で設定されている(クラスの生成、クラスの継承)。



PHPとJSは、PHPとPythonよりも似ている部分が多い。その分ちょっとした違いに注意が必要。(elseif と else ifとか)

>ご参考:phpとpythonの違いまとめ(対比表)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelで環境(開発環境と本番環境等)ごとに異なる値を定義する

環境(開発環境と本番環境等)ごとに異なる値

データベースの接続先とかメールの送信元等、開発環境と本番環境で異なる値にしたいことがあります
それを実現するためにわざわざif文を書く必要はありません

前提条件

eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

envファイルの作成

(1) envファイル作成
/sample/.envがすでに存在していると思います
/sample/.envをコピーして/sample/.env.localという名前のファイルにします

(2) 値の追記
/sample/.envに下記を追記
SAMPLE_KEY=SAMPLE_VALUE_PRD

/sample/.env.localに下記を追記
SAMPLE_KEY=SAMPLE_VALUE_LOCAL

configファイルの作成

(1) /sample/config/sample.phpを作成

sample.php
<?php

return [
    'sampleKey' => env('SAMPLE_KEY'),
];

env('SAMPLE_KEY')で先ほどenvファイルに追記したSAMPLE_KEYの値が取れます

Controllerにメソッド追加

(1) /sample/app/Http/Controllers/SampleController.phpにsettingメソッドを追記

    public function setting()
    {
        $data = ['key' => config('sample.sampleKey')];
        return view('sample.setting', $data);
    }

config('sample.sampleKey')で先ほどconfig/sample.phpに書いたsampleKey要素を取得できます
なぜここでenv('SAMPLE_KEY')ではなく、config('sample.sampleKey')で値を取得するのかは後述します

(2) /sample/routes/web.phpに下記を追記
Route::get('sample/setting', 'SampleController@setting');

viewの作成

/sample/resources/views/sample/setting.blade.phpファイル作成

setting.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        {{$key}}
    </body>
</html>

動作確認

apacheのhttpd.confに下記を追記
もしapacheにmod_envモジュールをインストールしていない方は、mod_envモジュールをインストールしてください

httpd.conf
SetEnv APP_ENV local

apache再起動してアクセス
http://localhost/laravelSample/sample/setting

実行結果

SAMPLE_VALUE_LOCAL

先ほど追記したSetEnvをコメントにする

httpd.conf
#SetEnv APP_ENV local

apache再起動してアクセス
http://localhost/laravelSample/sample/setting

実行結果

SAMPLE_VALUE_PRD

このようにapacheに設定した環境変数APP_ENVの値が.envファイルの接尾辞となり、
Laravelアプリケーションで読み込まれる.envファイルを変えることができます

configのキャッシュ

(1) コマンドラインで
cd sample
php artisan config:cache
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/bootstrap/cache/config.phpが現れます

/sample/config配下のファイルが/sample/bootstrap/cache/config.php一つにまとめられました
Laravelは/sample/bootstrap/cache/config.phpを読むようになります
これによりアプリケーションの処理速度があがります

(2) コマンドラインで
cd sample
php artisan config:clear
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/bootstrap/cache/config.phpが消えました

(3) Controllerでconfig関数を使った理由
先ほどControllerでenv('SAMPLE_KEY')ではなく、config('sample.sampleKey')で値を取得しました
その理由は
bootstrap/cache/config.phpをつくると、env関数の呼び出しはすべてnullを返すようになるLaravelの仕様のためです
したがって、.envファイルに記載した値は一度configファイルの配列に設定して、Controller以降ではconfig関数を使用して取得することになります

開発時はphp artisan config:cacheを実行することはないと思います
しかし、本番環境ではphp artisan config:cacheを実行してデプロイすることになると思います

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelで例外発生時Slackに通知する方法

概要

Laravelの通知と例外処理の勉強のために実装してみました。

Notificationに関する記事は数多くあり、公式ドキュメントでも解説されていますが、備忘録としてかんたんな流れを残しておきます。

環境

  • Laravel 6.0
  • PHP 7.2

事前準備

Guzzleとslack-notification-channelのインストール

$ composer install guzzlehttp/guzzle
$ composer install laravel/slack-notification-channel

SlackのWebhookURLを取得する

今回はenvの値をconfig経由で使用します。
webhookURL取得手順については割愛しますね...

slack.php
return [
    'name' => env('SLACK_NAME'),
    'channel' => env('SLACK_CHANNEL'),
    'webhook_url' => env('SLACK_WEBHOOK_URL'),
];

通知用クラスの作成

ひとまず,slackにメッセージを送信できるように実装します。
初期状態では,メール送信がデフォルトになっているので,slack用に変更してあげます。

App\Notifications\Slack.php;
<?php

namespace App\Notifications;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;

class Slack extends Notification
{
    use Queueable;

    protected $name;
    protected $channnel;
    protected $content;


    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($message)
    {
        $this->name = config(slack.name);
        $this->channel = config(slack.channnel);
        $this->content = $message;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }

    /**
     * @param $notifiable
     * @return $this
     */
    public function toSlack($notifiable)
    {
        return (new SlackMessage)
            ->from($this->name)
            ->to($this->channel)
            ->content($this->content);
    }
}

コンストラクタでmessageを受け取り、toSlack()でそのまま送信するシンプルな処理です。
通知を配信するチャンネルをslackにするため、via()の中を'slack'に変更します。

Slack通知用のルートを作成する

App\Service\Slack\SlackNotifiable.php
<?php

namespace App\Service\Slack;

use Illuminate\Notifications\Notifiable;
use App\Notifications\SlackNotification;
use Exception;
use Illuminate\Notifications\RoutesNotifications;

class SlackNotifiable
{
  use Notifiable;

  protected function routeNotificationForSlack()
  {
    return config('slack.webhook_url');
  }
}

実際にSlack通知をルートするために,routeNotificationForSlackを定義しWebhookURLを返しています。
Notifiableトレイトを読み込むことでnotify()で通知を送信できます。
これで,Slackにメッセージを送信する準備はOKです!

例外処理に通知を組み込む

Laravelのエラーハンドリングは基本的にapp\Exceptions\Handler.phpが担っています。
ざっくりした流れとしては

  1. report()で例外をキャッチ
  2. 親クラスであるIlluminate\Foundation\Exceptions\Handler.phpでrenderレスポンスのために条件分岐 ログインエラーなのか,バリデーションエラーなのか等々...
  3. render()でレスポンスを返す。

今回は、例外検知時に通知を送りたいので、report()を編集します。

App\ExceptionsHandler.php
public function report(Exception $exception)
    {
        $slackHook = new SlackNotifiable();
        $slackHook->notify(new Slack($exception));
        parent::report($exception);
    }

SlackNotifiableのインスタンスを作成し,notify()メソッドを実行することで通知を送っています。
引数にキャッチした例外$exceptionを渡しています。

Slack通知用クラスの修正

最後にpp\Notifications\Slack.phpで例外内容を通知するように修正します。

App\Notifications\Slack.php;
<?php

namespace App\Notifications;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;

class Slack extends Notification
{
    use Queueable;

    protected $name;
    protected $channnel;
    protected $exception;


    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(Exception $e)
    {
        $this->name = config(slack.name);
        $this->channel = config(slack.channnel);
        $this->exception = $e;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
    /**
     * @param $notifiable
     * @return $this
     */
    public function toSlack($notifiable)
    {
        $exception = $this->exception;

        return (new SlackMessage)
            ->from($this->name)
            ->to($this->channel)
            ->error()
            ->content('エラーを検知しました')
            ->attachment(function ($attachment) use ($exception) {
                $attachment
                    ->title(get_class($exception))
                    ->content($exception->getMessage());
            });
    }
}

コンストラクタでExceptionを受け取るように修正しています。
これでエラー内容をSlackで確認することができるようになりました!
スクリーンショット 2020-05-19 2.04.51.png

おわりに

最後まで読んでくださってありがとうございました。
至らぬ点など有りましたら、コメントで指摘して頂けるとありがたいです...

Laravelの通知処理を理解するのに良い勉強になりました。
次はキューとか使った非同期処理もやってみたいなぁ。

参考記事

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelで例外発生時にSlack通知する方法

概要

Laravelの通知と例外処理の勉強のために実装してみました。

Notificationに関する記事は数多くあり、公式ドキュメントでも解説されていますが、備忘録としてかんたんな流れを残しておきます。

環境

  • Laravel 6.0
  • PHP 7.2

事前準備

Guzzleとslack-notification-channelのインストール

$ composer install guzzlehttp/guzzle
$ composer install laravel/slack-notification-channel

SlackのWebhookURLを取得する

今回はenvの値をconfig経由で使用します。
webhookURL取得手順については割愛しますね...

config\slack.php
return [
    'name' => env('SLACK_NAME'),
    'channel' => env('SLACK_CHANNEL'),
    'webhook_url' => env('SLACK_WEBHOOK_URL'),
];

通知用クラスの作成

ひとまずslackにメッセージを送信できるように実装します。
初期状態ではメール送信がデフォルトになっているので、slack用に変更してあげます。

App\Notifications\Slack.php;
<?php

namespace App\Notifications;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;

class Slack extends Notification
{
    use Queueable;

    protected $name;
    protected $channnel;
    protected $content;


    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($message)
    {
        $this->name = config(slack.name);
        $this->channel = config(slack.channnel);
        $this->content = $message;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }

    /**
     * @param $notifiable
     * @return $this
     */
    public function toSlack($notifiable)
    {
        return (new SlackMessage)
            ->from($this->name)
            ->to($this->channel)
            ->content($this->content);
    }
}

コンストラクタでmessageを受け取り、toSlack()でそのまま送信するシンプルな処理です。
通知を配信するチャンネルをslackにするため、via()の中を'slack'に変更します。

Slack通知用のルートを作成する

App\Service\Slack\SlackNotifiable.php
<?php

namespace App\Service\Slack;

use Illuminate\Notifications\Notifiable;
use App\Notifications\SlackNotification;
use Exception;
use Illuminate\Notifications\RoutesNotifications;

class SlackNotifiable
{
  use Notifiable;

  protected function routeNotificationForSlack()
  {
    return config('slack.webhook_url');
  }
}

実際にSlack通知をルートするために、routeNotificationForSlack()を定義しWebhookURLを返しています。
Notifiableトレイトを読み込み、notify()で通知を送信できます。

これでSlackにメッセージを送信する準備はOKです!

例外処理に通知を組み込む

Laravelのエラーハンドリングは基本的にapp\Exceptions\Handler.phpが担っています。
ざっくりした流れとしては

  1. report()で例外をキャッチ
  2. 親クラスであるIlluminate\Foundation\Exceptions\Handler.phpでrenderレスポンスのために条件分岐 ログインエラーなのか,バリデーションエラーなのか等々...
  3. render()でレスポンスを返す。

今回は、例外検知時に通知を送りたいので、report()を編集します。

App\ExceptionsHandler.php
public function report(Exception $exception)
    {
        $slackHook = new SlackNotifiable();
        $slackHook->notify(new Slack($exception));
        parent::report($exception);
    }

SlackNotifiableのインスタンスを作成し,notify()メソッドを実行することで通知を送っています。
引数にキャッチした例外$exceptionを渡しています。

Slack通知用クラスの修正

最後にApp\Notifications\Slack.phpで例外内容を通知するように修正します。

App\Notifications\Slack.php;
<?php

namespace App\Notifications;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;

class Slack extends Notification
{
    use Queueable;

    protected $name;
    protected $channnel;
    protected $exception;


    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(Exception $e)
    {
        $this->name = config(slack.name);
        $this->channel = config(slack.channnel);
        $this->exception = $e;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
    /**
     * @param $notifiable
     * @return $this
     */
    public function toSlack($notifiable)
    {
        $exception = $this->exception;

        return (new SlackMessage)
            ->from($this->name)
            ->to($this->channel)
            ->error()
            ->content('エラーを検知しました')
            ->attachment(function ($attachment) use ($exception) {
                $attachment
                    ->title(get_class($exception))
                    ->content($exception->getMessage());
            });
    }
}

コンストラクタでExceptionを受け取るように修正しています。

これでエラー内容をSlackで確認することができるようになりました!
スクリーンショット 2020-05-19 2.04.51.png

おわりに

最後まで読んでくださってありがとうございました。
至らぬ点など有りましたら、コメントで指摘して頂けるとありがたいです...

Laravelの通知処理を理解するのに良い勉強になりました。
次はキューとか使った非同期処理もやってみたいなぁ。

参考記事

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelのExceptionをSlackで通知する

概要

Laravelの通知と例外処理の勉強のために実装してみました。

Notificationに関する記事は数多くあり、公式ドキュメントでも解説されていますが、備忘録としてかんたんな流れを残しておきます。

環境

  • Laravel 6.0
  • PHP 7.2

事前準備

Guzzleとslack-notification-channelのインストール

$ composer install guzzlehttp/guzzle
$ composer install laravel/slack-notification-channel

SlackのWebhookURLを取得する

今回はenvの値をconfig経由で使用します。
webhookURL取得手順については割愛しますね...

config\slack.php
return [
    'name' => env('SLACK_NAME'),
    'channel' => env('SLACK_CHANNEL'),
    'webhook_url' => env('SLACK_WEBHOOK_URL'),
];

通知用クラスの作成

ひとまずslackにメッセージを送信できるように実装します。
初期状態ではメール送信がデフォルトになっているので、slack用に変更してあげます。

App\Notifications\Slack.php;
<?php

namespace App\Notifications;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;

class Slack extends Notification
{
    use Queueable;

    protected $name;
    protected $channnel;
    protected $content;


    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($message)
    {
        $this->name = config(slack.name);
        $this->channel = config(slack.channnel);
        $this->content = $message;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }

    /**
     * @param $notifiable
     * @return $this
     */
    public function toSlack($notifiable)
    {
        return (new SlackMessage)
            ->from($this->name)
            ->to($this->channel)
            ->content($this->content);
    }
}

コンストラクタでmessageを受け取り、toSlack()でそのまま送信するシンプルな処理です。
通知を配信するチャンネルをslackにするため、via()の中を'slack'に変更します。

Slack通知用のルートを作成する

App\Service\Slack\SlackNotifiable.php
<?php

namespace App\Service\Slack;

use Illuminate\Notifications\Notifiable;
use App\Notifications\SlackNotification;
use Exception;
use Illuminate\Notifications\RoutesNotifications;

class SlackNotifiable
{
  use Notifiable;

  protected function routeNotificationForSlack()
  {
    return config('slack.webhook_url');
  }
}

実際にSlack通知をルートするために、routeNotificationForSlack()を定義しWebhookURLを返しています。
Notifiableトレイトを読み込み、notify()で通知を送信できます。

これでSlackにメッセージを送信する準備はOKです!

例外処理に通知を組み込む

Laravelのエラーハンドリングは基本的にapp\Exceptions\Handler.phpが担っています。
ざっくりした流れとしては

  1. report()で例外をキャッチ
  2. 親クラスであるIlluminate\Foundation\Exceptions\Handler.phpでrenderレスポンスのために条件分岐 ログインエラーなのか,バリデーションエラーなのか等々...
  3. render()でレスポンスを返す。

今回は、例外検知時に通知を送りたいので、report()を編集します。

App\ExceptionsHandler.php
public function report(Exception $exception)
    {
        $slackHook = new SlackNotifiable();
        $slackHook->notify(new Slack($exception));
        parent::report($exception);
    }

SlackNotifiableのインスタンスを作成し,notify()メソッドを実行することで通知を送っています。
引数にキャッチした例外$exceptionを渡しています。

Slack通知用クラスの修正

最後にApp\Notifications\Slack.phpで例外内容を通知するように修正します。

App\Notifications\Slack.php;
<?php

namespace App\Notifications;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;

class Slack extends Notification
{
    use Queueable;

    protected $name;
    protected $channnel;
    protected $exception;


    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(Exception $e)
    {
        $this->name = config(slack.name);
        $this->channel = config(slack.channnel);
        $this->exception = $e;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
    /**
     * @param $notifiable
     * @return $this
     */
    public function toSlack($notifiable)
    {
        $exception = $this->exception;

        return (new SlackMessage)
            ->from($this->name)
            ->to($this->channel)
            ->error()
            ->content('エラーを検知しました')
            ->attachment(function ($attachment) use ($exception) {
                $attachment
                    ->title(get_class($exception))
                    ->content($exception->getMessage());
            });
    }
}

コンストラクタでExceptionを受け取るように修正しています。

これでエラー内容をSlackで確認することができるようになりました!
スクリーンショット 2020-05-19 2.04.51.png

おわりに

最後まで読んでくださってありがとうございました。
至らぬ点など有りましたら、コメントで指摘して頂けるとありがたいです...

Laravelの通知処理を理解するのに良い勉強になりました。
次はキューとか使った非同期処理もやってみたいなぁ。

参考記事

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

route 書き方の違い

どこかでパラメータ付きURLを生成する

$url = route('users.edit', ['user' => $user->id]);
$url = route('users.edit', ['user' => $user]);

第二引数のuserがidでもmodelでも動く理由

結論

route関数を司るDatabase/eloquent/Model.phpにある$primarykeyで決定する
$primarykeにidが代入されているため['user' => $user]と書いてもidが参照され、取ることができる
スクリーンショット 2020-05-18 23.43.38.png

ここまでの過程

どこかでroute関数を定義する。

indexController.php
public function index ()
    {
        route();
    }

このrouteを⌘+クリックすると
laravelのhelper関数が集約されてるところに飛ぶ
ここではフォーマットを整えるぐらい

helpers.php
function route($name, $parameters = [], $absolute = true)
    {
        return app('url')->route($name, $parameters, $absolute);
    }

次にこのapp->のrouteが何かを辿る

ここではgetByNameはよくて、toRouteに飛びます

UrlGenerater.php
public function route($name, $parameters = [], $absolute = true)
    {
        if (! is_null($route = $this->routes->getByName($name))) {
            return $this->toRoute($route, $parameters, $absolute);
        }

        throw new InvalidArgumentException("Route [{$name}] not defined.");
    }

次にrouteUrlはいいので、formatParametersに飛びます

UrlGenerater.php
protected function toRoute($route, $parameters, $absolute)
    {
        return $this->routeUrl()->to(
            $route, $this->formatParameters($parameters), $absolute
        );
    }

肝心なのはgetRouteKey()です。

UrlGenerater.php
public function formatParameters($parameters)
    {
        $parameters = Arr::wrap($parameters);

        foreach ($parameters as $key => $parameter) {
            if ($parameter instanceof UrlRoutable) {
                $parameters[$key] = $parameter->getRouteKey();
            }
        }

        return $parameters;
    }

コメントアウトされている様にmodelのkeyでvalueをget
そして、UrlRoutabeleがinterfaceされてます。
この親はDatabase/eloquent/Model.phpになるのでそこで、結論が定義されてます。

UrlRoutable.php
interface UrlRoutable
{
    /**
     * Get the value of the model's route key.
     *
     * @return mixed
     */
    public function getRouteKey();

2番目の書き方の注意であり前提

①tableにidが設定されていること
②結論の$primarykeyでidが定義されていること

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mac PHP 出力を改行する

目的

  • 出力内容に改行をつける方法をまとめる

実施環境

  • 下記のサービスにてブラウザ上で実行した。

  • 下記を実行する。(ちなみにMac OSで\を入力する方法は「option」 + 「¥」を同時に押下する。)

    //出力文字の最後に改行を入れたい場合(一行での出力はあまり意味がないがforeachなどの繰り返し時処理を確認したい時に役立つ)
    echo '出力したい文字'."\n";
    //下記の様に出力される(末尾に改行が入るため通常の出力では変化なし)
    // 出力したい文字
    
    //出力文字の途中で改行を入れたい場合
    echo '出力したい文字A'."\n".'出力したい文字B';
    //下記の様に出力される
    // 出力したい文字A
    // 出力したい文字B
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel Telescopeのタイムゾーンを強制的に日本時間にする

LaravelのTelescopeにおいて、タイムゾーンを指定してるにもかかわらず日本時間表示ができなかったので、強制的に変えてみました!

localTime()を下記のように修正

vendor/laravel/telescope/resources/js/base.js
        localTime(time) {
            return moment.tz(time,'Asia/Tokyo')
                .format('YYYY-MM-DD HH:mm:ss');
        },

   cd /LARAVEL_PATH/vendor/telescope
   npm run prod 
   cd /LARAVEL_PATH
   php artisan telescope:publish --force

cross-envをインストールする必要あり
ない場合は

npm install cross-env

以上です(^^)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む