- 投稿日:2020-11-27T23:20:33+09:00
Codeignater3を使ったMPAサイトからNuxt.js+Vueへのサイトリニューアル
はじめに
Vue.js(CDN版)を採用したPHP動的サイトから、Nuxt.js+Vueを使ったいわゆるSPAサイトへのリニューアルを敢行した。
経緯と歴史
最初は、フレームワークを使わないサイトとして設計したが、のちにSmatryを採用し、Viewとロジックを分離した第二世代をリリース。その後、Codeignater3を採用し、本格的にPHPフレームワークを採用した第三世代と進化していったが、リプレースの切っ掛けはいずれも機能拡張を繰り返し、いずれも 現状に限界を感じよりモダンな技術を採用していった経緯がある 。
今回は何が限界だったのか
Vueライブラリの複雑化
当初はJqueryを採用していたが、Vue.jsの導入に合わせライブラリが複雑化し、バージョンアップへの不安と煩雑さがつきまとうことになった。
痒いところに手が届かないフレームワークとViewのカスタマイズの煩雑化
UIフレームワークとして採用していたMaterializeはVue前提ではないため、開発を進めるにつれCSSをカスタマイズを行う面が多くなり、フレームワークのメリットが少なくなるとともに、CSSの開発に多くの時間が取られることになった。
更新手順およびViewの煩雑化・複雑化
ページが複雑化するに伴い、PHPのinclude機能で使い回すView画面がスパゲティ化するようになり、速度向上で導入したPWAのServiceWorkerのバージョンを手作業で書き換えるなどの更新の手間が極めて煩雑になりつつあった。
ベストプラクティスな技術を試したい
こうした状況が重なり、最新のフロントエンドのベストプラクティスとも言える技術で再構築を検討することとなった。当初はログインシステムの関係からVue-Cliのみを導入し、MPAのままの構築を行う事も検討したが、ユーザーへのID・パスワードの再設定のデメリットを考慮しても、Firebase Authenticationを採用した方が、セキュリティ面やプログラミング・維持などあらゆる場面でメリットがあると判断。Nuxt.js+VueによるSPAを採用することとなった。
開発
バックエンド
SPAとなれば、必然的にフロントとバックエンドが分離されるが、リニューアル前より無限スクロールを採用していたことから部分的にCodeignaterにAPIを実装し、axiosを用いた非同期通信で情報を取得ていたこともあり、開発時間短縮のために、バックエンドは引き続きCodeignaterを改良およびリファクタリングしてそのまま採用することとなった。
フロントエンド
Vue3およびTSの採用については現時点では見送ることとして、Webにサンプルなどのドキュメントが豊富なVue2.6.11とJSを採用した。
UIフレームワークはvuetifyを採用。最初はとっつきにくかったけど、高機能でデザインの完成度が高いので慣れてしまえば本当に楽。最初からコンポーネント至高なので、こちらも楽だが、無秩序にやってしまうとまたスパゲティになるので注意したい。開発
10月頭に開発がスタートをして、形になるリリースまで1ヶ月半。細かな機能追加と調整に二週間程度で完成することになった。
感想
今回のリニューアルは技術的に本当に勉強になりましたし、サイトの管理と開発が本当に楽になりました。フロントとバックを分離した疎結合化は精神的にも楽になった感があります。Nuxt.jsは現時点でのベストプラクティス的な技術ではありますが、技術的に未熟で採用できないという事情はあるにしろ、基礎を習得しないと応用はできないとはいえ、随分と遠回りした印象もあります。これまでは煩雑な保守管理に時間を浪費していましたが、今後のページはペラ1でも無い限りNuxt.jsファーストで行きたいと思います。
- 投稿日:2020-11-27T23:05:42+09:00
CentOS 8にPHP 8.0, PHP-FPM 8.0をインストール(Remi's RPM repository)
はじめに
Remi's RPM repositoryを利用してCentOS8にPHP8.0をインストール
親記事:PHP, PHP-FPMの各種インストール方法とEOLまとめ
参考:Remi's RPM repositoryサポート
本手法で導入した場合、PHP: Supported Versions/PHP: Unsupported Branchesより、2023-11-26がEOLになると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。note
- 他のPHPモジュールを入れていた場合、下記コマンドでモジュールのリセットが必要
# dnf module reset phpLOG
インストール
# cat /etc/redhat-release CentOS Linux release 8.2.2004 (Core) # dnf install -y https://rpms.remirepo.net/enterprise/remi-release-8.rpm ... 略 # dnf module install -y php:remi-8.0 # dnf install -y which ... 略php-fpm起動/停止
# systemctl start php-fpm # systemctl status php-fpm ● php-fpm.service - The PHP FastCGI Process Manager Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2020-11-27 13:59:40 UTC; 41s ago Main PID: 271 (php-fpm) Status: "Processes active: 0, idle: 5, Requests: 0, slow: 0, Traffic: 0req/sec" Tasks: 6 (limit: 8920) Memory: 19.5M CGroup: /docker/acc0e606a3a3ae90da45bde51910a623ac10fc7d9822f68a03c8eb973969839e/system.slice/php-fpm.service tq271 php-fpm: master process (/etc/php-fpm.conf) tq272 php-fpm: pool www tq273 php-fpm: pool www tq274 php-fpm: pool www tq275 php-fpm: pool www mq276 php-fpm: pool www Nov 27 13:59:40 acc0e606a3a3 systemd[1]: Starting The PHP FastCGI Process Manager... Nov 27 13:59:40 acc0e606a3a3 systemd[1]: Started The PHP FastCGI Process Manager.# systemctl stop php-fpm # systemctl status php-fpm ● php-fpm.service - The PHP FastCGI Process Manager Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; vendor preset: disabled) Active: inactive (dead) Nov 27 13:59:40 acc0e606a3a3 systemd[1]: Starting The PHP FastCGI Process Manager... Nov 27 13:59:40 acc0e606a3a3 systemd[1]: Started The PHP FastCGI Process Manager. Nov 27 14:01:05 acc0e606a3a3 systemd[1]: Stopping The PHP FastCGI Process Manager... Nov 27 14:01:05 acc0e606a3a3 systemd[1]: Stopped The PHP FastCGI Process Manager.php-fpm自動起動設定/設定解除
# systemctl enable php-fpm Created symlink /etc/systemd/system/multi-user.target.wants/php-fpm.service → /usr/lib/systemd/system/php-fpm.service. # systemctl list-unit-files --type=service |grep php-fpm php-fpm.service enabled# systemctl disable php-fpm Removed /etc/systemd/system/multi-user.target.wants/php-fpm.service. # systemctl list-unit-files --type=service |grep php-fpm php-fpm.service disabled各種確認
# which php /usr/bin/php # php -v PHP 8.0.0 (cli) (built: Nov 24 2020 17:04:03) ( NTS gcc x86_64 ) Copyright (c) The PHP Group Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies # php -i | grep php.ini Configuration File (php.ini) Path => /etc Loaded Configuration File => /etc/php.ini # which php-fpm /usr/sbin/php-fpm # /usr/sbin/php-fpm -v PHP 8.0.0 (fpm-fcgi) (built: Nov 24 2020 17:04:03) Copyright (c) The PHP Group Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies # dnf module info php:remi-8.0 Failed to set locale, defaulting to C.UTF-8 Last metadata expiration check: 0:01:10 ago on Fri Nov 27 14:03:05 2020. Name : php Stream : remi-8.0 [e] [a] Version : 20201127071524 Context : 00000000 Architecture : x86_64 Profiles : common [d] [i], devel, minimal Default profiles : common Repo : remi-modular Summary : PHP scripting language Description : Alternative php 8.0 module. The remi-8.0 stream provides more recent versions and more packages than default 8.0 stream. Requires : platform:[el8] Artifacts : apcu-panel-0:5.1.18-7.el8.remi.8.0.noarch : apcu-panel-0:5.1.19-1.el8.remi.8.0.noarch : libzip-0:1.7.3-1.el8.remi.x86_64 : libzip-devel-0:1.7.3-1.el8.remi.x86_64 : libzip-tools-0:1.7.3-1.el8.remi.x86_64 : php-0:8.0.0-1.el8.remi.x86_64 : php-0:8.0.0~rc5-9.el8.remi.x86_64 : php-ast-0:1.0.10-2.el8.remi.8.0.x86_64 : php-ast-0:1.0.10-3.el8.remi.8.0.x86_64 : php-bcmath-0:8.0.0-1.el8.remi.x86_64 : php-bcmath-0:8.0.0~rc5-9.el8.remi.x86_64 : php-brotli-0:0.11.1-2.el8.remi.8.0.x86_64 : php-brotli-0:0.11.1-3.el8.remi.8.0.x86_64 : php-cli-0:8.0.0-1.el8.remi.x86_64 : php-cli-0:8.0.0~rc5-9.el8.remi.x86_64 : php-common-0:8.0.0-1.el8.remi.x86_64 : php-common-0:8.0.0~rc5-9.el8.remi.x86_64 : php-componere-0:3.1.2-1.el8.remi.8.0.x86_64 : php-dba-0:8.0.0-1.el8.remi.x86_64 : php-dba-0:8.0.0~rc5-9.el8.remi.x86_64 : php-dbg-0:8.0.0-1.el8.remi.x86_64 : php-dbg-0:8.0.0~rc5-9.el8.remi.x86_64 : php-devel-0:8.0.0-1.el8.remi.x86_64 : php-devel-0:8.0.0~rc5-9.el8.remi.x86_64 : php-embedded-0:8.0.0-1.el8.remi.x86_64 : php-embedded-0:8.0.0~rc5-9.el8.remi.x86_64 : php-enchant-0:8.0.0-1.el8.remi.x86_64 : php-enchant-0:8.0.0~rc5-9.el8.remi.x86_64 : php-fedora-autoloader-0:1.0.1-2.el8.remi.noarch : php-fedora-autoloader-devel-0:1.0.1-2.el8.remi.noarch : php-ffi-0:8.0.0-1.el8.remi.x86_64 : php-ffi-0:8.0.0~rc5-9.el8.remi.x86_64 : php-fpm-0:8.0.0-1.el8.remi.x86_64 : php-fpm-0:8.0.0~rc5-9.el8.remi.x86_64 : php-gd-0:8.0.0-1.el8.remi.x86_64 : php-gd-0:8.0.0~rc5-9.el8.remi.x86_64 : php-geos-0:1.0.0-17.el8.remi.8.0.x86_64 : php-geos-0:1.0.0-18.el8.remi.8.0.x86_64 : php-gmp-0:8.0.0-1.el8.remi.x86_64 : php-gmp-0:8.0.0~rc5-9.el8.remi.x86_64 : php-imap-0:8.0.0-1.el8.remi.x86_64 : php-imap-0:8.0.0~rc5-9.el8.remi.x86_64 : php-intl-0:8.0.0-1.el8.remi.x86_64 : php-intl-0:8.0.0~rc5-9.el8.remi.x86_64 : php-ldap-0:8.0.0-1.el8.remi.x86_64 : php-ldap-0:8.0.0~rc5-9.el8.remi.x86_64 : php-litespeed-0:8.0.0-1.el8.remi.x86_64 : php-litespeed-0:8.0.0~rc5-9.el8.remi.x86_64 : php-lz4-0:0.3.7-1.el8.remi.8.0.x86_64 : php-lz4-0:0.4.0-1.el8.remi.8.0.x86_64 : php-maxminddb-0:1.7.0-3.el8.remi.8.0.x86_64 : php-maxminddb-0:1.8.0-2.el8.remi.8.0.x86_64 : php-mbstring-0:8.0.0-1.el8.remi.x86_64 : php-mbstring-0:8.0.0~rc5-9.el8.remi.x86_64 : php-mysqlnd-0:8.0.0-1.el8.remi.x86_64 : php-mysqlnd-0:8.0.0~rc5-9.el8.remi.x86_64 : php-oci8-0:8.0.0-1.el8.remi.x86_64 : php-oci8-0:8.0.0~rc5-9.el8.remi.x86_64 : php-odbc-0:8.0.0-1.el8.remi.x86_64 : php-odbc-0:8.0.0~rc5-9.el8.remi.x86_64 : php-opcache-0:8.0.0-1.el8.remi.x86_64 : php-opcache-0:8.0.0~rc5-9.el8.remi.x86_64 : php-pdlib-0:1.0.2-4.el8.remi.8.0.x86_64 : php-pdlib-0:1.0.2-5.el8.remi.8.0.x86_64 : php-pdo-0:8.0.0-1.el8.remi.x86_64 : php-pdo-0:8.0.0~rc5-9.el8.remi.x86_64 : php-pdo-dblib-0:8.0.0-1.el8.remi.x86_64 : php-pdo-dblib-0:8.0.0~rc5-9.el8.remi.x86_64 : php-pdo-firebird-0:8.0.0-1.el8.remi.x86_64 : php-pdo-firebird-0:8.0.0~rc5-9.el8.remi.x86_64 : php-pear-1:1.10.12-2.el8.remi.noarch : php-pear-1:1.10.12-4.el8.remi.noarch : php-pecl-amqp-0:1.10.2-2.el8.remi.8.0.x86_64 : php-pecl-amqp-0:1.10.2-3.el8.remi.8.0.x86_64 : php-pecl-apcu-0:5.1.18-7.el8.remi.8.0.x86_64 : php-pecl-apcu-0:5.1.19-1.el8.remi.8.0.x86_64 : php-pecl-apcu-devel-0:5.1.18-7.el8.remi.8.0.x86_64 : php-pecl-apcu-devel-0:5.1.19-1.el8.remi.8.0.x86_64 : php-pecl-apfd-0:1.0.2-1.el8.remi.8.0.x86_64 : php-pecl-apfd-0:1.0.2-2.el8.remi.8.0.x86_64 : php-pecl-base58-0:0.1.4-4.el8.remi.8.0.x86_64 : php-pecl-base58-0:0.1.4-5.el8.remi.8.0.x86_64 : php-pecl-bitset-0:3.0.1-5.el8.remi.8.0.x86_64 : php-pecl-couchbase3-0:3.0.4-2.el8.remi.8.0.x86_64 : php-pecl-csv-0:0.3.1-2.el8.remi.8.0.x86_64 : php-pecl-datadog-trace-0:0.50.0-1.el8.remi.8.0.x86_64 : php-pecl-datadog-trace-0:0.51.0-1.el8.remi.8.0.x86_64 : php-pecl-dbase-0:7.1.0~RC2-1.el8.remi.8.0.x86_64 : php-pecl-dio-0:0.2.0-3.el8.remi.8.0.x86_64 : php-pecl-dio-0:0.2.0-4.el8.remi.8.0.x86_64 : php-pecl-ds-0:1.3.0-1.el8.remi.8.0.x86_64 : php-pecl-ds-0:1.3.0-2.el8.remi.8.0.x86_64 : php-pecl-env-0:0.2.1-10.el8.remi.8.0.x86_64 : php-pecl-env-0:0.2.1-11.el8.remi.8.0.x86_64 : php-pecl-event-0:3.0.0-1.el8.remi.8.0.x86_64 : php-pecl-fann-0:1.1.1-18.el8.remi.8.0.x86_64 : php-pecl-fann-0:1.1.1-19.el8.remi.8.0.x86_64 : php-pecl-geoip-0:1.1.1-14.el8.remi.8.0.x86_64 : php-pecl-geospatial-0:0.2.1-3.el8.remi.8.0.x86_64 : php-pecl-grpc-0:1.34.0~RC1-1.el8.remi.8.0.x86_64 : php-pecl-grpc-0:1.34.0~RC2-1.el8.remi.8.0.x86_64 : php-pecl-http-0:4.0.0~beta1-1.el8.remi.8.0.x86_64 : php-pecl-http-0:4.0.0~beta1-2.el8.remi.8.0.x86_64 : php-pecl-http-devel-0:4.0.0~beta1-1.el8.remi.8.0.x86_64 : php-pecl-http-devel-0:4.0.0~beta1-2.el8.remi.8.0.x86_64 : php-pecl-http-message-0:0.2.2-3.el8.remi.8.0.x86_64 : php-pecl-http-message-0:0.2.2-4.el8.remi.8.0.x86_64 : php-pecl-http-message-devel-0:0.2.2-3.el8.remi.8.0.x86_64 : php-pecl-http-message-devel-0:0.2.2-4.el8.remi.8.0.x86_64 : php-pecl-igbinary-0:3.1.5-3.el8.remi.8.0.x86_64 : php-pecl-igbinary-0:3.1.6-1.el8.remi.8.0.x86_64 : php-pecl-igbinary-devel-0:3.1.5-3.el8.remi.8.0.x86_64 : php-pecl-igbinary-devel-0:3.1.6-1.el8.remi.8.0.x86_64 : php-pecl-imagick-0:3.4.4-12.el8.remi.8.0.x86_64 : php-pecl-imagick-0:3.4.4-14.el8.remi.8.0.x86_64 : php-pecl-imagick-devel-0:3.4.4-12.el8.remi.8.0.x86_64 : php-pecl-imagick-devel-0:3.4.4-14.el8.remi.8.0.x86_64 : php-pecl-inotify-0:2.0.0-11.el8.remi.8.0.x86_64 : php-pecl-inotify-0:2.0.0-12.el8.remi.8.0.x86_64 : php-pecl-ip2location-0:8.1.0-1.el8.remi.8.0.x86_64 : php-pecl-ip2location-0:8.1.1-1.el8.remi.8.0.x86_64 : php-pecl-ip2proxy-0:3.0.0-1.el8.remi.8.0.x86_64 : php-pecl-ip2proxy-0:3.0.1-1.el8.remi.8.0.x86_64 : php-pecl-json-post-0:1.0.2-3.el8.remi.8.0.x86_64 : php-pecl-json-post-0:1.0.2-4.el8.remi.8.0.x86_64 : php-pecl-krb5-0:1.1.4-1.el8.remi.8.0.x86_64 : php-pecl-krb5-0:1.1.4-2.el8.remi.8.0.x86_64 : php-pecl-krb5-devel-0:1.1.4-1.el8.remi.8.0.x86_64 : php-pecl-krb5-devel-0:1.1.4-2.el8.remi.8.0.x86_64 : php-pecl-lzf-0:1.6.8-3.el8.remi.8.0.x86_64 : php-pecl-lzf-0:1.6.8-4.el8.remi.8.0.x86_64 : php-pecl-mailparse-0:3.1.1-1.el8.remi.8.0.x86_64 : php-pecl-mailparse-0:3.1.1-2.el8.remi.8.0.x86_64 : php-pecl-mcrypt-0:1.0.3-4.el8.remi.8.0.x86_64 : php-pecl-memcached-0:3.1.5-2.el8.remi.8.0.x86_64 : php-pecl-memcached-0:3.1.5-3.el8.remi.8.0.x86_64 : php-pecl-memprof-0:2.1.1-1.el8.remi.8.0.x86_64 : php-pecl-memprof-0:2.1.2-1.el8.remi.8.0.x86_64 : php-pecl-mongodb-0:1.9.0-1.el8.remi.8.0.x86_64 : php-pecl-mongodb-0:1.9.0~rc1-1.el8.remi.8.0.x86_64 : php-pecl-msgpack-0:2.1.1-2.el8.remi.8.0.x86_64 : php-pecl-msgpack-0:2.1.1-3.el8.remi.8.0.x86_64 : php-pecl-msgpack-devel-0:2.1.1-2.el8.remi.8.0.x86_64 : php-pecl-msgpack-devel-0:2.1.1-3.el8.remi.8.0.x86_64 : php-pecl-mustache-0:0.9.2-1.el8.remi.8.0.x86_64 : php-pecl-mysqlnd-azure-0:1.1.1-2.el8.remi.8.0.x86_64 : php-pecl-oauth-0:2.0.7-1.el8.remi.8.0.x86_64 : php-pecl-oauth-0:2.0.7-2.el8.remi.8.0.x86_64 : php-pecl-pcov-0:1.0.6-4.el8.remi.8.0.x86_64 : php-pecl-pq-0:2.1.8-1.el8.remi.8.0.x86_64 : php-pecl-pq-0:2.1.8-2.el8.remi.8.0.x86_64 : php-pecl-protobuf-0:3.13.0.1-1.el8.remi.8.0.x86_64 : php-pecl-psr-0:1.0.0-5.el8.remi.8.0.x86_64 : php-pecl-psr-0:1.0.1-1.el8.remi.8.0.x86_64 : php-pecl-psr-devel-0:1.0.0-5.el8.remi.8.0.x86_64 : php-pecl-psr-devel-0:1.0.1-1.el8.remi.8.0.x86_64 : php-pecl-raphf-0:2.0.1-2.el8.remi.8.0.x86_64 : php-pecl-raphf-0:2.0.1-3.el8.remi.8.0.x86_64 : php-pecl-raphf-devel-0:2.0.1-2.el8.remi.8.0.x86_64 : php-pecl-raphf-devel-0:2.0.1-3.el8.remi.8.0.x86_64 : php-pecl-redis5-0:5.3.2-1.el8.remi.8.0.x86_64 : php-pecl-redis5-0:5.3.2~RC2-1.el8.remi.8.0.x86_64 : php-pecl-rpminfo-0:0.5.1-5.el8.remi.8.0.x86_64 : php-pecl-rpminfo-0:0.5.1-6.el8.remi.8.0.x86_64 : php-pecl-rrd-0:2.0.1-8.el8.remi.8.0.x86_64 : php-pecl-rrd-0:2.0.1-9.el8.remi.8.0.x86_64 : php-pecl-runkit7-0:4.0.0~a1-1.el8.remi.8.0.x86_64 : php-pecl-runkit7-0:4.0.0~a2-1.el8.remi.8.0.x86_64 : php-pecl-scrypt-0:1.4.2-9.el8.remi.8.0.x86_64 : php-pecl-selinux-0:0.5.0-3.el8.remi.8.0.x86_64 : php-pecl-selinux-0:0.5.0-4.el8.remi.8.0.x86_64 : php-pecl-solr2-0:2.5.1-1.el8.remi.8.0.x86_64 : php-pecl-solr2-0:2.5.1-2.el8.remi.8.0.x86_64 : php-pecl-ssdeep-0:1.1.0-6.el8.remi.8.0.x86_64 : php-pecl-ssdeep-0:1.1.0-7.el8.remi.8.0.x86_64 : php-pecl-ssh2-0:1.2-3.el8.remi.8.0.x86_64 : php-pecl-ssh2-0:1.2-4.el8.remi.8.0.x86_64 : php-pecl-swoole4-0:4.5.8-2.el8.remi.8.0.x86_64 : php-pecl-swoole4-0:4.5.9-1.el8.remi.8.0.x86_64 : php-pecl-swoole4-devel-0:4.5.8-2.el8.remi.8.0.x86_64 : php-pecl-swoole4-devel-0:4.5.9-1.el8.remi.8.0.x86_64 : php-pecl-translit-0:0.7.0-5.el8.remi.8.0.x86_64 : php-pecl-translit-0:0.7.1-1.el8.remi.8.0.x86_64 : php-pecl-uuid-0:1.1.0-4.el8.remi.8.0.x86_64 : php-pecl-uuid-0:1.2.0-1.el8.remi.8.0.x86_64 : php-pecl-vips-0:1.0.12-2.el8.remi.8.0.x86_64 : php-pecl-vips-0:1.0.12-3.el8.remi.8.0.x86_64 : php-pecl-xattr-0:1.4.0-3.el8.remi.8.0.x86_64 : php-pecl-xattr-0:1.4.0-4.el8.remi.8.0.x86_64 : php-pecl-xdebug3-0:3.0.0-1.el8.remi.8.0.x86_64 : php-pecl-xdebug3-0:3.0.0~rc1-1.el8.remi.8.0.x86_64 : php-pecl-xdiff-0:2.0.1-8.el8.remi.8.0.x86_64 : php-pecl-xhprof-0:2.2.2-1.el8.remi.8.0.x86_64 : php-pecl-xhprof-0:2.2.3-1.el8.remi.8.0.x86_64 : php-pecl-xlswriter-0:1.3.6-8.el8.remi.8.0.x86_64 : php-pecl-xlswriter-0:1.3.6-9.el8.remi.8.0.x86_64 : php-pecl-xmldiff-0:1.1.2-15.el8.remi.8.0.x86_64 : php-pecl-xmldiff-0:1.1.2-16.el8.remi.8.0.x86_64 : php-pecl-xmldiff-devel-0:1.1.2-15.el8.remi.8.0.x86_64 : php-pecl-xmldiff-devel-0:1.1.2-16.el8.remi.8.0.x86_64 : php-pecl-xmlrpc-0:1.0.0~DEV.20200602-3.el8.remi.8.0.x86_64 : php-pecl-xmlrpc-0:1.0.0~DEV.20200602-4.el8.remi.8.0.x86_64 : php-pecl-yac-0:2.2.1-2.el8.remi.8.0.x86_64 : php-pecl-yac-0:2.2.1-3.el8.remi.8.0.x86_64 : php-pecl-yaconf-0:1.1.0-2.el8.remi.8.0.x86_64 : php-pecl-yaconf-0:1.1.0-3.el8.remi.8.0.x86_64 : php-pecl-yaconf-devel-0:1.1.0-2.el8.remi.8.0.x86_64 : php-pecl-yaconf-devel-0:1.1.0-3.el8.remi.8.0.x86_64 : php-pecl-yaml-0:2.2.0~b2-1.el8.remi.8.0.x86_64 : php-pecl-yaml-0:2.2.0~b2-2.el8.remi.8.0.x86_64 : php-pecl-yaz-0:1.2.3-4.el8.remi.8.0.x86_64 : php-pecl-zip-0:1.19.1-1.el8.remi.8.0.x86_64 : php-pecl-zip-0:1.19.2-1.el8.remi.8.0.x86_64 : php-pecl-zmq-0:1.1.3-13.el8.remi.8.0.x86_64 : php-pecl-zmq-0:1.1.3-14.el8.remi.8.0.x86_64 : php-pgsql-0:8.0.0-1.el8.remi.x86_64 : php-pgsql-0:8.0.0~rc5-9.el8.remi.x86_64 : php-phpiredis-0:1.0.1-1.el8.remi.8.0.x86_64 : php-phpiredis-0:1.0.1-2.el8.remi.8.0.x86_64 : php-process-0:8.0.0-1.el8.remi.x86_64 : php-process-0:8.0.0~rc5-9.el8.remi.x86_64 : php-pspell-0:8.0.0-1.el8.remi.x86_64 : php-pspell-0:8.0.0~rc5-9.el8.remi.x86_64 : php-realpath-turbo-0:2.0.0-1.el8.remi.8.0.x86_64 : php-realpath-turbo-0:2.0.0-2.el8.remi.8.0.x86_64 : php-smbclient-0:1.0.0-8.el8.remi.8.0.x86_64 : php-smbclient-0:1.0.0-9.el8.remi.8.0.x86_64 : php-snappy-0:0.2.0-1.el8.remi.8.0.x86_64 : php-snappy-0:0.2.0-2.el8.remi.8.0.x86_64 : php-snmp-0:8.0.0-1.el8.remi.x86_64 : php-snmp-0:8.0.0~rc5-9.el8.remi.x86_64 : php-soap-0:8.0.0-1.el8.remi.x86_64 : php-soap-0:8.0.0~rc5-9.el8.remi.x86_64 : php-sodium-0:8.0.0-1.el8.remi.x86_64 : php-sodium-0:8.0.0~rc5-9.el8.remi.x86_64 : php-sqlsrv-0:5.9.0~preview1-1.el8.remi.8.0.x86_64 : php-tidy-0:8.0.0-1.el8.remi.x86_64 : php-tidy-0:8.0.0~rc5-9.el8.remi.x86_64 : php-xml-0:8.0.0-1.el8.remi.x86_64 : php-xml-0:8.0.0~rc5-9.el8.remi.x86_64 : php-zstd-0:0.9.0-3.el8.remi.8.0.x86_64 : php-zstd-0:0.9.0-4.el8.remi.8.0.x86_64 : php-zstd-devel-0:0.9.0-3.el8.remi.8.0.x86_64 : php-zstd-devel-0:0.9.0-4.el8.remi.8.0.x86_64 : unit-php-0:1.20.0-1.el8.remi.8.0.x86_64 : unit-php-0:1.21.0-1.el8.remi.8.0.x86_64 : xhprof-0:2.2.2-1.el8.remi.8.0.noarch : xhprof-0:2.2.3-1.el8.remi.8.0.noarch Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled, [a]ctive
- 投稿日:2020-11-27T22:58:22+09:00
CentOS 7にPHP-FPM 8.0をインストール(Remi's RPM repository)
はじめに
Remi's RPM repositoryを利用してCentOS7にPHP-FPM8.0をインストール
親記事:PHP, PHP-FPMの各種インストール方法とEOLまとめ
参考:Remi's RPM repositoryサポート
本手法で導入した場合、PHP: Supported Versions/PHP: Unsupported Branchesより、2023-11-26がEOLになると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。note
- インストール後の更新は
yum --enablerepo=remi-php80 update
LOG
インストール
# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) # yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm ... 略 # yum install -y --enablerepo=remi-php80 php-fpm which ... 略php-fpm起動/停止
# systemctl start php-fpm # systemctl status php-fpm ● php-fpm.service - The PHP FastCGI Process Manager Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2020-11-27 13:55:54 UTC; 4s ago Main PID: 333 (php-fpm) Status: "Ready to handle connections" CGroup: /docker/78c480b53127eafffc6bfcdb3eb1e0031f072a827d8afb4f2b0bbd97949deba5/docker/78c480b53127eafffc6bfcdb3eb1e0031f072a827d8afb4f2b0bbd97949deba5/system.slice/php-fpm.service tq333 php-fpm: master process (/etc/php-fpm.conf) tq334 php-fpm: pool www tq335 php-fpm: pool www tq336 php-fpm: pool www tq337 php-fpm: pool www mq338 php-fpm: pool www ? 333 php-fpm: master process (/etc/php-fpm.conf) Nov 27 13:55:54 78c480b53127 systemd[1]: Starting The PHP FastCGI Process Manager... Nov 27 13:55:54 78c480b53127 systemd[1]: Started The PHP FastCGI Process Manager.# systemctl stop php-fpm # systemctl status php-fpm ● php-fpm.service - The PHP FastCGI Process Manager Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; vendor preset: disabled) Active: inactive (dead) Nov 27 13:55:54 78c480b53127 systemd[1]: Starting The PHP FastCGI Process Manager... Nov 27 13:55:54 78c480b53127 systemd[1]: Started The PHP FastCGI Process Manager. Nov 27 13:56:13 78c480b53127 systemd[1]: Stopping The PHP FastCGI Process Manager... Nov 27 13:56:13 78c480b53127 systemd[1]: Stopped The PHP FastCGI Process Manager.php-fpm自動起動設定/設定解除
# systemctl enable php-fpm Created symlink from /etc/systemd/system/multi-user.target.wants/php-fpm.service to /usr/lib/systemd/system/php-fpm.service. # systemctl list-unit-files --type=service |grep php-fpm php-fpm.service enabled# systemctl disable php-fpm Removed symlink /etc/systemd/system/multi-user.target.wants/php-fpm.service. # systemctl list-unit-files --type=service |grep php-fpm php-fpm.service disabled各種確認
# which php which: no php in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin) # which php-fpm /usr/sbin/php-fpm # php-fpm -v PHP 8.0.0 (fpm-fcgi) (built: Nov 24 2020 17:04:03) Copyright (c) The PHP Group Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies # yum info php-fpm Loaded plugins: fastestmirror, ovl Loading mirror speeds from cached hostfile * base: ftp.riken.jp * epel: nrt.edge.kernel.org * extras: ftp.riken.jp * remi-safe: ftp.riken.jp * updates: ftp.riken.jp Installed Packages Name : php-fpm Arch : x86_64 Version : 8.0.0 Release : 1.el7.remi Size : 6.2 M Repo : installed From repo : remi-php80 Summary : PHP FastCGI Process Manager URL : http://www.php.net/ License : PHP and Zend and BSD and MIT and ASL 1.0 and NCSA Description : PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI : implementation with some additional features useful for sites of : any size, especially busier sites.
- 投稿日:2020-11-27T22:47:37+09:00
CentOS 7にPHP 8.0をインストール(Remi's RPM repository)
はじめに
Remi's RPM repositoryを利用してCentOS7にPHP8.0をインストール
親記事:PHP, PHP-FPMの各種インストール方法とEOLまとめ
参考:Remi's RPM repositoryサポート
本手法で導入した場合、PHP: Supported Versions/PHP: Unsupported Branchesより、2023-11-26がEOLになると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。note
- インストール後の更新は
yum --enablerepo=remi-php80 update
LOG
インストール
# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) # yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm ... 略 # yum install -y --enablerepo=remi-php80 php which ... 略各種確認
# which php /usr/bin/php # php -v PHP 8.0.0 (cli) (built: Nov 24 2020 17:04:03) ( NTS gcc x86_64 ) Copyright (c) The PHP Group Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies # php -i | grep php.ini Configuration File (php.ini) Path => /etc Loaded Configuration File => /etc/php.ini # yum info php Loaded plugins: fastestmirror, ovl Loading mirror speeds from cached hostfile * base: ftp.riken.jp * epel: nrt.edge.kernel.org * extras: ftp.riken.jp * remi-safe: ftp.riken.jp * updates: ftp.riken.jp Installed Packages Name : php Arch : x86_64 Version : 8.0.0 Release : 1.el7.remi Size : 5.1 M Repo : installed From repo : remi-php80 Summary : PHP scripting language for creating dynamic web sites URL : http://www.php.net/ License : PHP and Zend and BSD and MIT and ASL 1.0 and NCSA Description : PHP is an HTML-embedded scripting language. PHP attempts to make it : easy for developers to write dynamically generated web pages. PHP also : offers built-in database integration for several commercial and : non-commercial database management systems, so writing a : database-enabled webpage with PHP is fairly simple. The most common : use of PHP coding is probably as a replacement for CGI scripts. : : The php package contains the module (often referred to as mod_php) : which adds support for the PHP language to Apache HTTP Server.
- 投稿日:2020-11-27T22:09:48+09:00
PHPで階乗計算
まずは普通に再帰関数で。
test1.php<?php function factorial($n) { if($n > 0) return $n * factorial($n - 1); return 1; } for($n = 1; $n <= 180; ++$n) { echo "$n! = ", factorial($n), "\n"; }結果
1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = 5040 8! = 40320 9! = 362880 10! = 3628800 11! = 39916800 12! = 479001600 13! = 6227020800 14! = 87178291200 15! = 1307674368000 16! = 20922789888000 17! = 355687428096000 18! = 6402373705728000 19! = 121645100408832000 20! = 2432902008176640000 21! = 5.1090942171709E+19 22! = 1.1240007277776E+21 23! = 2.5852016738885E+22 24! = 6.2044840173324E+23 : 中略 : 168! = 2.5260757449732E+302 169! = 4.2690680090047E+304 170! = 7.257415615308E+306 171! = INF 172! = INF 173! = INF :当然ですが、21!から指数表記に、171!以降はINFに。
ちょっと物足りないので、文字列と配列で1桁ずつ10進数演算するよう変更。test2.php<?php function factorial($n) { if($n > 0) return intMul($n, factorial($n - 1)); return 1; } function intMul($a, $b) { $a = "$a"; $b = "$b"; $r = []; $al = strlen($a); $bl = strlen($b); for($i = 0; $i < $al; ++$i) { $_a = $al - 1 - $i; for($j = 0; $j < $bl; ++$j) { $_b = $bl - 1 - $j; $k = $i + $j; if(!isset($r[$k])) $r[$k] = 0; $r[$k] += $a[$_a] * $b[$_b]; if($r[$k] > 9) { $k1 = $k + 1; if(!isset($r[$k1])) $r[$k1] = 0; $r[$k1] += (int)($r[$k] / 10); $r[$k] %= 10; } } } return strrev(implode('', $r)); } for($n = 1; $n <= 180; ++$n) { echo "$n! = ", factorial($n), "\n"; }結果
1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = 5040 8! = 40320 9! = 362880 10! = 3628800 11! = 39916800 12! = 479001600 13! = 6227020800 14! = 87178291200 15! = 1307674368000 16! = 20922789888000 17! = 355687428096000 18! = 6402373705728000 19! = 121645100408832000 20! = 2432902008176640000 21! = 51090942171709440000 22! = 1124000727777607680000 23! = 25852016738884976640000 24! = 620448401733239439360000 : 中略 : 180! = 20089606249913429965 …中略… 986039603200000000000000000000000000000000000000000000しっかり表示されるものの、1桁ずつ計算しているので結構遅いです。
私の普段使いの数年前のノートPCだと、5000!程度の計算でも数十秒かかります。$n = 5000; $start = hrtime(true); $result = factorial($n); $end = hrtime(true); echo "$n! = $result\n", ($end - $start) / 1e9, "\n"; // 5000! = 422857792660554 …中略… 5509378334720000 …中略… 0000000000 // 47.1204944ある程度の桁数をまとめて計算できるようにしてみます。
echo 999999999 * 999999999; // 999999998000000001 echo 9999999999 * 9999999999; // 9.999999998E+199桁同士までなら大丈夫そうなのでとりあえず9桁で。
test3.php<?php function factorial($n) { if($n > 0) return intMul($n, factorial($n - 1)); return 1; } define('DIGIT', 9); define('NUMBER', 10 ** DIGIT); define('F', '%0'. DIGIT. 'd'); function intMul($a, $b) { $a = "$a"; $b = "$b"; $a_ = $a; $ra = []; $asn = strlen($a) / DIGIT; for($i = 0; $i < $asn; ++$i) { array_push($ra, (int)substr($a_, -DIGIT)); $a_ = substr($a_, 0, -DIGIT); } $b_ = $b; $rb = []; $bsn = strlen($b) / DIGIT; for($i = 0; $i < $bsn; ++$i) { array_push($rb, (int)substr($b_, -DIGIT)); $b_ = substr($b_, 0, -DIGIT); } $c = []; for($i = 0; $i < count($ra); ++$i) { for($j = 0; $j < count($rb); ++$j) { $p = $i + $j; if(!isset($c[$p])) $c[$p] = 0; $c[$p] += $ra[$i] * $rb[$j]; if($c[$p] >= NUMBER) { if(!isset($c[$p + 1])) $c[$p + 1] = 0; $c[$p + 1] += (int)($c[$p] / NUMBER); $c[$p] %= NUMBER; } } } for($i = 0; $i < count($c) - 1; ++$i) $c[$i] = sprintf(F, $c[$i]); return implode('', array_reverse($c)); } $n = 5000; $start = hrtime(true); $result = factorial($n); $end = hrtime(true); echo "$n! = $result\n", ($end - $start) / 1e9, "\n"; // 5000! = 422857792660554 …中略… 5509378334720000 …中略… 0000000000 // 4.277748310倍くらい早くなりました。
自分で組むのはひとまず置いて、GMPに階乗関数gmp_fact()があるのでこれを使ってみます。
test4.php<?php $n = 5000; $start = hrtime(true); $result = gmp_fact($n); $end = hrtime(true); echo "$n! = ", gmp_strval($result), "\n", ($end - $start) / 1e9, "\n"; // 5000! = 422857792660554 …中略… 5509378334720000 …中略… 0000000000 // 0.0003974更に10000倍くらい早くなりました。
1000000!の場合
// 1000000! = 82639316883312400623 …中略… 25617650584125440000 …中略… 0000000000 // 0.342245510000000!の場合
// 10000000! = 12024234005159034561 …中略… 03073025741946880000 …中略… 0000000000 // 6.7120242階乗を使いたいけれど自分で書きたいわけではないのなら、
gmp_fact()
を使うのが良さそうですね。追記
5000!に約4.2秒かかっていた自前計算版(test3.php)も、乗算処理を階乗計算用としてループ内に入れて配列/文字列変換処理コストを節約することで、同じアルゴリズムのままでも3倍くらい早くなりました。
それでもgmp_fact()
には到底及びませんが。test5.php<?php function factorial($f) { if($f < 0 || $f !== (int)$f) return false; $d = 9; $dn = 10 ** $d; $df = "%0{$d}d"; $c = [1]; for($n = 1; $n <= $f; ++$n) { $ra = $c; $c = [0]; $b_ = "$n"; $rb = []; $bsn = strlen($n) / $d; for($i = 0; $i < $bsn; ++$i) { array_push($rb, (int)substr($b_, -$d)); $b_ = substr($b_, 0, -$d); } for($i = 0; $i < count($ra); ++$i) { for($j = 0; $j < count($rb); ++$j) { $p = $i + $j; if(!isset($c[$p])) $c[$p] = 0; $c[$p] += $ra[$i] * $rb[$j]; if($c[$p] >= $dn) { $p1 = $p + 1; if(!isset($c[$p1])) $c[$p1] = 0; $c[$p1] += (int)($c[$p] / $dn); $c[$p] %= $dn; } } } } for($i = 0; $i < count($c) - 1; ++$i) $c[$i] = sprintf($df, $c[$i]); return implode('', array_reverse($c)); } $n = 5000; $start = hrtime(true); $result = factorial($n); $end = hrtime(true); echo "$n! = $result\n", ($end - $start) / 1e9, "\n"; // 5000! = 422857792660554 …中略… 5509378334720000 …中略… 00000000 // 1.3479136
- 投稿日:2020-11-27T19:28:12+09:00
PHP8(PHP-FPM)のメモ
環境
- CentOS7
(元々色々なバージョンを動かすのに使ってた)epel, remi のリポジトリの追加は済んでる環境(下記)
yum -y install epel-release yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpmPHP8と諸々インストール
yum -y install php80 php80-php php80-php-mbstring php80-php-pdo php80-php-mysqlnd php80-php-gd php80-php-xml php80-php-fpm設定
cd /etc/opt/remi/php80/php-fpm.d/ cp -a www.conf www.conf-original vi www.confwww.conflisten = 127.0.0.1:9080 pm = ondemandいろんなバージョンのPHPを動かしているのでポートはそれぞれ被らないように設定
vi /etc/httpd/conf.d/virtualhost.confvirtualhost.conf<Directory "/path/to/php80/document_root"> <FilesMatch \.php$> SetHandler "proxy:fcgi://localhost:9080" # ← www.conf に指定したポート番号 </FilesMatch> </Directory>更新して起動する
service httpd configtest systemctl start php80-php-fpm systemctl status php80-php-fpm systemctl enable php80-php-fpm systemctl restart httpd
おわり。
Apacheのデフォルトで使用されるバージョンを変える
正解かどうかわからないけど、
PHPのバージョンごとにあるApacheのモジュールを無効化すればOK。リネームなり削除して読み込まれるモジュールを変える。
なお、複数生きている場合はファイル名昇順で先に来るものが当たる(たぶん)
※ パッケージ更新すると復活するかも…cd /etc/httpd/conf.modules.d mv 15-php72-php.conf 15-php72-php.conf_bak systemctl restart httpdPHP7のソースをPHP8で動かしてみて引っかかったところと変更内容
自動DI で使ってたリフレクションの一部がコケた
// ↓ NGになった $tempReflectionClass = $reflectionParameter->getClass(); // ↓ OK $type = $reflectionParameter->getType(); $tempReflectionClass = $type !== null && !$type->isBuiltin() ? new \ReflectionClass($type->getName()) : null ;is_callable を静的でないクラスメソッドに対して
クラス名とメソッド名で読んでいたのがNGになった。// ↓ NGになった is_callable([クラス名, 静的でないメソッド名]); // ↓ OK is_callable([インスタンス, 静的でないメソッド名]);
- 投稿日:2020-11-27T19:07:06+09:00
学習を応用し自分で考えたプログラム(随時更新予定)
今回は、お客様アンケート(仮)を作成 2020/11/27
<?php //評価が0の時にアドバイスをお願いし、0以上の時は感謝の言葉を伝えるプログラム echo 'より良いサービスを制作するため、アンケートにご協力お願いいたします' . PHP_EOL; echo '評価(5点満点中):'; $status = trim(fgets(STDIN)); $a = $status; if ($a > 1) { echo 'ご利用ありがとうございました' . PHP_EOL; } else { echo '品質向上の為何かアドバイスをいただけないでしょうか' . PHP_EOL; } $Impressions = trim(fgets(STDIN)); //aが1より大きければご利用ありがとうございました!aが1より小さければアドバイスのお願い //標準入力と、半角スペース削除の処理、if文のみを使用した処理です。これからもアウトプットしていきます!
Gif動画の作り方 (参考にさせていただきましたありがとうございます)
https://youtu.be/aQOpbP3hr0A
- 投稿日:2020-11-27T19:07:06+09:00
学習を応用し0からプログラム作成(随時更新予定)
今回は、お客様アンケート(仮)を作成 2020/11/27
<?php //評価が0の時にアドバイスをお願いし、0以上の時は感謝の言葉を伝えるプログラム echo 'より良いサービスを制作するため、アンケートにご協力お願いいたします' . PHP_EOL; echo '評価(5点満点中):'; $status = trim(fgets(STDIN)); $a = $status; if ($a > 1) { echo 'ご利用ありがとうございました' . PHP_EOL; } else { echo '品質向上の為何かアドバイスをいただけないでしょうか' . PHP_EOL; } $Impressions = trim(fgets(STDIN)); //aが1より大きければご利用ありがとうございました!aが1より小さければアドバイスのお願い //標準入力と、半角スペース削除の処理、if文のみを使用した処理です。これからもアウトプットしていきます!
Gif動画の作り方 (参考にさせていただきましたありがとうございます)
https://youtu.be/aQOpbP3hr0AHomebrew使って、ffmpegをインストールして簡単に作成
動画の有るディレクトリまで移動
ls -lh
動画の容量確認
ffmpeg -i sample.mov -r (数字)(変更したいファイルの名前).gif
-rの後ろに1~20を設定。1秒間に表示したい画像の数大きくなればなるほどスムーズにみれる例
ffmpeg -i sample.mov -r 10 sample.gif
enterで完了GIFの確認は選択して、スペースキーを押す
*他にも様々なオプションがある.
- 投稿日:2020-11-27T18:52:47+09:00
LaravelAdminのシャーディング対応
本記事は、サムザップ Advent Calendar 2020 #2 の12/6の記事です。
LaravelAdminは、いわゆる管理画面のフレームワークです。(公式: https://laravel-admin.org/docs/en/)
シンプルながらデザインが整っていて、いちから作るよりはよい機能がそろっています。また、CRUDで作られていて、定型的な表示や操作ならモデル指定ぐらいで作れたりします。
一方で、ゲーム開発のサーバでは負荷分散のためにシャーディングをしていることが多く、データベースとテーブルを複数組み合わせてひとつのデータを示していることがよくあります。
LaravelAdminでは、そのままこれらのデータを扱うことができません。
ここではそんなLaravelAdminでシャーディングしたデータを扱うためのいくつかの方法を述べてみます。何が問題?
LaravelAdminではGrid、Formなどいくつかの表示や操作の仕組みを提供していて、それらのクラスに対してモデルを渡したり表示内容などを記述するといった作り方をしています。
渡すモデルは、あらかじめ生成したモデルを渡すことができるので、シャーディングされたDBやテーブルをシャーディングキーで特定することが事前にできれば、そのシャーディング先を示すモデルを扱うことはできます。
ただシャーディングされたデータをそのままGridに渡すと、全件表示されてしまいます。たとえばユーザーIDをシャーディングキーにしているものなら、ユーザーIDを指定しても、ほかのユーザーのデータも表示されてしまいます。
ほかにも条件による絞り込み機能など、サブ的な仕組みには、シャーディングキーを呼び出し元と揃えたい場合があり、シャーディングキーをどうやって渡すかがポイントになりがちです。シャーディングに対応したgridの作成
Gridは便利な機能ですが、そのままでは扱えないので、LaravelAdminのコードを改造することにしました。
考え方として、シャーディングキーをあらかじめフィルターのように使えば、Gridの表示の際、シャーディングキーに合わせた表示がされるはずです。この仕組みを「デフォルトのフィルター」としてGridに用意してやればいいわけです。
vendor/encore/laravel-admin/src/Grid.phpに以下のコードを追加します。Grid.php/** * default filter key * @var string */ protected $defaultFilterKey; /** * default filter value * @var mixed */ protected $defaultFilterValue; /** * Add default filter. * * @return void */ public function addDefaultFilter($key, $value) { $this->defaultFilterKey = $key; $this->defaultFilterValue = $value; }同じGrid.phpのapplyQuery()では、フィルタに基づく条件の設定などを行っています、ここでdefaultFilterKey、defaultFilterValueをwhereして、検索条件に加えます。
Grid.php/** * @return array|Collection|mixed */ public function applyQuery() { if (!empty($this->defaultFilterKey)) { $this->model()->where($this->defaultFilterKey, $this->defaultFilterValue); } $this->applyQuickSearch(); $this->applyColumnFilter(); $this->applyColumnSearch(); $this->applySelectorQuery(); }使い方は次の通りです。ここでは$userIdがシャーディングキーになります。
$hogemodels = new HogeModel(); //シャードをセット。DBが決まる $hogemodels->setShard($userId); //Gridの初期化コールバックでシャードキーを設定。表示を$userIdのものに指定 Grid::init( function(Grid $grid) use ($userId) { $grid->addDefaultFilter('user_id', $userId); }); return Admin::content(function (Content $content) use ($hogemodels, $userId) { //Gridの利用 $content->body(Admin::grid($hogemodels, function (Grid $grid) use ($userId) { $grid->user_id('ユーザーID')->sortable(); })); });シャーディングキーを渡して表示条件指定を行う
フィルター機能にはhiddenフィールドを記述できる仕組みがあるので、それでシャーディングキーを渡すようにすると、うまく呼び出せます。
以下のようにfilterのコールバックでhidden()を記述します。$userIdがシャーディングキーです。public function resultview(Request $request) { $userId = $request->user_id; $hogemodels = new LogTrophies(); $hogemodels->setShard($userId); Grid::init( function(Grid $grid) use ($userId) { $grid->addDefaultFilter('user_id', $userId); }); return Admin::content(function (Content $content) use ($hogemodels, $userId) { $content->body(Admin::grid($hogemodels, function (Grid $grid) use ($userId) { $grid->user_id('ユーザーID')->sortable(); $grid->perPages([100, 200, 500, 1000]); $grid->filter(function ($filter) use ($userId) { $filter->disableIdFilter(); $filter->hidden('user_id', $userId); $filter->equal('type', 'type'); $filter->equal('key', 'key'); $filter->equal('value', 'value'); }); })); }); }シャーディングキーを渡してEditフォームを利用する
Editフォームにはhiddenフィールドの記述方法がないので、シャーディングキーを渡すのにちょっと頭を使います。
Editフォームを呼び出すために使うURLには、呼び出し元のURLが使われます。そこで$grid->setResourceでシャーディングキーを混ぜたURLにしてやることで、シャーディングキーを渡せます。
大元のGridで以下のようにして$content->body(Admin::grid($hogemodels, function (Grid $grid) use ($userId) { $grid->setResource('/admin/hoge/resultview/' . $userId); //Edit Action用にユーザーID渡すため $grid->user_id('ユーザーID')->sortable(); }));routes.phpは以下のようにシャーディングキーであるUserIdと、テーブルのユニークIDであるidを両方取るように記述します。
routes.php$router->get('/hoge/resultview/{userId}/{id}/edit', 'HogeController@edit');Editの受け側には、userId、idの2つの引数を取るように記述します
public function edit($userId, $id) { $hogemodels = new UserBirthdays(); $hogemodels->setShard($userId); Grid::init( function(Grid $grid) use ($userId) { $grid->addDefaultFilter('user_id', $userId); }); return Admin::content(function (Content $content) use ($hogemodels, $userId) { $content->header('hoge情報'); $content->description('編集'); $content->body( Admin::form($hogemodels, function (Form $form) use ($hogemodels, $userId) { $form->display('ユーザーID')->default($userId); $form->setaction('/admin/hoge/modification'); }) ); }); }まとめ
LaravelAdminは便利なフレームワークですが、便利であるがゆえに仕組みが決まっているため、最初は作法がわからずとっつきにくいかもしれません。でも、いろいろコードを調べると、便利なものが多くあります。ぜひいろいろ試してみてください。
明日は @hiroki_shimada の記事です。
- 投稿日:2020-11-27T15:41:47+09:00
Laravelバリデーション integerとnumericの動作の違い
- Laravel6.x
- PHP7.4
紛らわしいので調べました。
integer の挙動
入力値が整数で構成された文字列か数値であることをバリデートします。
※実際の判定文はこちら
// vendor\laravel\framework\src\Illuminate\Validation\Concerns\ValidatesAttributes.php public function validateInteger($attribute, $value) { return filter_var($value, FILTER_VALIDATE_INT) !== false; }numericの挙動
入力値が数字または数値形式の文字列であることをバリデートします。
※実際の判定文はこちら
// vendor\laravel\framework\src\Illuminate\Validation\Concerns\ValidatesAttributes.php public function validateNumeric($attribute, $value) { return is_numeric($value); }比較
- ○:バリデーションチェックを通過する
- ×:バリデーションチェックに引っかかりエラーになる
検証値 integer
numeric
regex:/^[0-9]+$/i
'0'
○ ○ ○ '123'
○ ○ ○ '0123'
× 注意! ○ ○ '+1'
○ 注意! ○ × '-1'
○ 注意! ○ × '0.1'
× ○ × '1.1'
× ○ × '113-0012'
× × × '090-111-222'
× × × '123'
× × × おまけ 動作確認用
<?php $list = ['0', '123', '0123', '+1', '-1', '0.1', '1.1', '114-0012', '090-2222-3333', '123']; foreach ($list as $value) { echo "$value "; if (filter_var($value, FILTER_VALIDATE_INT) !== false) { echo " |integer: ○"; } else { echo " |integer: ×"; } if (is_numeric($value)) { echo " |numeric: ○"; } else { echo " |numeric: ×"; } if (preg_match("/^[0-9]+$/i", $value)) { echo " |regex: ○"; } else { echo " |regex: ×"; } echo "\n"; } ?>
- 投稿日:2020-11-27T15:39:43+09:00
PHP/Laravel用語集
はじめに
PHP/Laravelに関する基本的な用語を簡単にまとめました。
特に初学者の場合、用語の意味や意図が分かっていないまま学習をしていると「今何をしてるんだ?」となりがちなので、迷子にならない為にも用語の意味を知っておくことが重要だと思い記事にしました。私自身、勉強中の身ですので間違っている箇所などありましたら、Twitter(@Tii_engineering)のDMなどでご指摘いただけたら幸いです。
随時更新予定です。
MVCフレームワーク
Model(モデル)、View(ビュー)、Controller(コントローラー)の各機能に分けて整理し、これらのパーツを作ることで開発を行う。
Routing(ルーティング)
アクセスを設定している情報(ルート)を管理する機能。
特定のアドレスにアクセスした時、どの処理を呼び出して実行するかを管理するもの。
「〇〇というアドレスにアクセスしたら、××という処理を呼び出す」という関連付けを行なっている。
Model(モデル)
データ処理全般を担当。データベースアクセスに関する処理全般を扱う。
View(ビュー)
画面表示を担当。
Controllerの指示によって アクセスしてきたユーザーのブラウザに表示するデータを生成する。(HTMLファイルを出力するところのようなイメージ)
Controller(コントローラー)
全体の制御を担当。
必要に応じてModelからデータを取得したり、Viewを利用して画面表示を作成したりする。
Blade
シンプルにHTMLファイルを書くように書くことのできるテンプレートエンジン。
通常のPHPスクリプトファイルを記述するより効率的に作ることができる。
テンプレートを継承し新たなテンプレートを定義したり、レイアウトの一部をセクションとしてはめ込むことができる。
パス(path:通り道)
ファイルやフォルダの場所。
(ファイル名を含む場合と含まない場合がある。)
Migration(マイグレーション)
データベースのバージョン管理機能。
データベースのテーブルを作成・削除等する機能も持つ。
Validation(バリデーション)
Modelでデータを保存する前に、フォームからデータを送信されてきた値が正しい形式で書かれているかどうか、データの不備をあらかじめ防ぐために検証する仕組み
Auth
facade (ファサード)という機能で、ユーザーを認証しログインを管理する機能を自動生成してくれる機能。
composer
Laravelを構成するたくさんの公開ライブラリを矛盾がない状態で管理するツール。
ライブラリ同士は相互に複雑な依存関係がるが、これらの依存関係の管理を一手に引き受けてくれるのがcomposer。
Webpack
CSSやJavaScriptなど複数に分割されているファイルを1つにまとめることができる。
ソースコードを圧縮し、接続速度が早くなる。
Laravel Mix
WebpackやsassをLaravel用に使いやすくオーバーラップしているツール。
Webpackやsassはそれぞれ環境構築などを行うのに時間がかかるがLaravel Mixを使えば設定ファイルに数行記述するだけで、自動的に圧縮等の処理ができる。
GET
指定したURLの内容を取り出すための要求で、最も基本的なHTTPメソッド。
ブラウザからURLを入力してwebページを開くときには、GETメソッドのHTTPリクエストを送っている。
POST
URLに対して情報を要求するだけでなく、クライアントからさまざまなデータを送信することができる。
主にデータを更新するような処理に使われています。
テーブル
分類されたデータベースの種類ごとの単位。
データベースは複数のテーブルを保持し、テーブルごとにデータを管理している。
カラム
データベースの列に相当するもの。「属性」を意味する。
レコード
データそのものを意味する。
インスタンス
データベースとユーザーの間を仲介する役割がある。
インスタンスを介してデータベースを操作することで、データの安全性やパフォーマンスの向上につながる。インスタンスは『データベースにアクセスするための過程』であり、データベースは『データを格納したファイル』という関係性。
スキーマ
データベースの設計図
必要なデータの洗い出しや、そのデータの格納整理のルールを決める。(全体を理解するために割り当てられた『構造』)
データベースでは、そのような作業を『スキーマを定義する』と呼ぶ。
Eloquent ORM
ORMとは、レコードをオブジェクトとして扱えるようにするための仕組み。
Laravelには「Eloquent」というORMが内臓されている。
このEloquentを使って、モデルとデータベースとのやり取りを行うようにしています。
リレーション
テーブルの関連付け。
「Aさんが投稿した記事」というように、ユーザーと記事のテーブルを関連付けることを言う。
デプロイ
公開用のサーバーを用意し、そのサーバーに作成したアプリケーションのインストールを行い本稼働させること。
- 投稿日:2020-11-27T14:58:28+09:00
Laravel6 Unitテスト時に「Maximum function nesting level~」のエラーが出た
目的
- しょーもないミスで時間を費やしてしまったので反省の意味も含めてエラー原因などをメモ的にまとめる
前提情報
- LaravelのUnitテストを実行したところ「Error: Maximum function nesting level of '256' reached, aborting!」というエラーが出た。
- テストではServiceを呼び出し、紐付いたRepositoryからデータを取得する事ができるかを確認していた。
原因
- Serviceクラスの依存注入でそのServiceクラス自体を依存注入してしまっていた。
- さらにServiceクラス内のメソッドでそのメソッドを呼び出す処理を記載していた。
わかりにくいと思うので下記に図を記載する。
上記でなんとなくご理解いただけたと思うがUnitテストで呼び出しているServiceクラスのメソッドが自身を呼び出すようになってしまっていた。
当該ループが256回に達したため、エラーを出力して処理が停止した。
改善策
- 投稿日:2020-11-27T14:34:27+09:00
【VSCode】PHPの関数が未定義とのエラーが発生。原因は拡張機能のバージョンだった。
- 投稿日:2020-11-27T14:16:30+09:00
DBを使わず時間制限付きトークンを発行する
新規会員登録やパスワードリセットなどで、期間限定のトークンを発行することがあります。普通はトークンの発行時にトークン自身と有効期限をDBに登録し、トークン検証時にレコードの有効期限を確認します。
ですが、さまざまな事情でDBにトークンを記録したくないとか、そもそもDBが使用できないというような場合があります。そういうときにDBを使用せずに期間限定トークンを発行する方法を考えてみました。
クリティカルな用途には向かないと思いますので、実際に採用するかどうかは慎重にご検討ください。
アイデア
アイデアとしては、トークン内にトークン発行日時を埋め込んでしまえばいいというものです。
トークンを解読して発行日時を書き換えられたら意味がないので、トークンは一方向ハッシュ化します。
一方向ハッシュ化したら発行側でもトークンを検証できませんが、そこは現在日時を使って再度トークンを生成しなおすことで対応します。
実装
実装は以下のようになります。
function generate_token($salt) { $epoch = time(); return _generate_token($salt, $epoch); } function verify_token($salt, $token) { $epoch = time(); $new_token = _generate_token($salt, $epoch); return $token == $new_token; } function _generate_token($salt, $epoch) { return crypt((string)$epoch, $salt); }これで有効期間1秒のトークンが実装できました。
有効期間1秒ではさすがに使い物になりません。有効期間を1時間にする場合、3600秒前までトークン検証を繰り返します。
function verify_token($salt, $token) { $epoch = time(); for($i = 0; $i < 3600; $i++) { $new_token = _generate_token($salt, $epoch - $i); if($token == $new_token) { return true; } } return false; }検証のたびに3600回もループを回していては負荷が問題になりますので、エポック秒を 3600 で割って使います。
function _generate_token($salt, $epoch) { return crypt((string)floor($epoch / 3600), $salt); }しかしこれでは有効期間は1秒から3600秒のどれかになってしまいます。12時台であれば、12時0分でも12時30分でも12時59分でも、全部有効期限は12時59分59秒ってことですね。運良く12時直後にトークンを発行したら1時間近く有効ですが、12時59分付近だと有効期限は1分になってしまい、さすがに実用的ではありません。
そこで以下のように修正します。
function verify_token($salt, $token) { $epoch = time(); $new_token = _generate_token($salt, $epoch); if($token == $new_token) { return true; } $new_token = _generate_token($salt, $epoch - 3600); if($token == $new_token) { return true; } return false; }これで有効期間は1時間から1時間59分59秒となりました。1時間有効なトークンと言いつつ最長で2時間近く有効になりますので、かなりいい加減な仕様になります。つまりは、その程度のいい加減さが許される程度の用途にしか使えないということです。
欠点
他にも欠点がありまして、トークンにユーザを特定する情報を埋め込むことができません。通常のトークン実装であれば DB をトークンで検索してレコードに紐づけてあったユーザIDなりを取得すればいいのですが、DB を使用していませんから取得できる情報はユーザから渡されるもののみになります。ですので、ユーザIDなどの情報を別パラメータで引き回しておく必要があります。
https://example.com/?token=xxx // × https://example.com/?userid=yyy&token=xxx // 〇
- 投稿日:2020-11-27T14:00:25+09:00
Laraveを触って1年経ったのでTIPS
本当は2年くらいかもしれない
確認バージョンは Laravel 7.26.1
よく使うコマンド
ネームスペースとか考慮するとコマンドから作った方が良いです。でもコピペしちゃう
make系
# マイグレーション作成 php artisan make:migration create_xxxxx_table # モデル&ファクトリー&シーダー作成(app/) php artisan make:model Models/Xxxx -fs # コントローラー作成(app/Http/Controllers/) php artisan make:controller Api/XxxxController --model=Models/Xxxx --api # フォームリクエスト作成(app/Http/Requests/) php artisan make:request Api/Xxxx/Store # コマンド作成(app/Console/Commands/) php artisan make:command Xxxx ### ide-helperが導入されていれば # ide_helper:generate php artisan ide-helper:generate # ide_helper:models php artisan ide-helper:models -Ndb系
# マイグレーション実行 php artisan migrate # マイグレーションを一つ戻す php artisan migrate:rollback --step=1 # DB初期化&DatabaseSeeder実行 php artisan migrate:fresh --seed # シーダー実行 php artisan db:seed --class=UserSeederキャッシュを消す
# 全消し php artisan optimize:clear # optimize:clearの中身の実態は下記コマンド php artisan view:clear && \ php artisan cache:clear && \ php artisan route:clear && \ php artisan config:clear && \ php artisan clear-compiledちなみに間違ってもローカル開発環境で
php artisan config:cache
は使わないよう注意してください。
phpunitを走らせた際にキャッシュ化した.envの環境変数が使われてしまいます。
間違えた場合はphp artisan config:clear
してください。公式にも書いてる!
https://readouble.com/laravel/7.x/ja/configuration.htmlFactory
公式Faker
https://github.com/fzaninotto/Faker日本語ソース
https://github.com/fzaninotto/Faker/blob/master/src/Faker/Provider/ja_JP# ランダム英数字生成(unique使っても衝突してしまう場合) $faker->unique()->regexify('[a-zA-Z0-9]{1,20}')Routing
- Laravelでapiを叩いたときにjsonが返ってこない問題
php artisan route:list > route.txt
で吐き出すと楽ルーディングの書き方について
個人的にはHTTPメソッドごとにアクションを指定した方がいいかと思います。
Route::resourceを使ってデフォルトアクションを指定できるんですが、ワナがあります。
下記のように公開・下書きで投稿の処理を丸ごと分けたいなどした時に下記のようなルーティングになるかと思います。api.php
Route::resource('publish/posts', 'Publish\PostController')->only([ 'index', 'store', 'show', 'update', 'destroy', ]); Route::resource('draft/posts', 'Draft\PostController')->only([ 'index', 'store', 'show', 'update', 'destroy', ]);処理的には問題ないですが、
php artisan route:cache
(本番環境での高速化に必要)した際にname被りでエラーになります。
なのでシンプルにメソッドごとに書いた方が良いかと思います(いずれresourceで表現できないURIの方が多くなるので)Route::get('/publish/posts', 'Publish\PostController@index'); Route::post('/publish/posts', 'Publish\PostController@store'); Route::get('/publish/posts/{id}', 'Publish\PostController@show'); Route::patch('/publish/posts/{id}', 'Publish\PostController@update'); Route::delete('/publish/posts/{id}', 'Publish\PostController@destroy'); Route::get('/draft/posts', 'Draft\PostController@index'); Route::post('/draft/posts', 'Draft\PostController@store'); Route::get('/draft/posts/{id}', 'Draft\PostController@show'); Route::patch('/draft/posts/{id}', 'Draft\PostController@update'); Route::delete('/draft/posts/{id}', 'Draft\PostController@destroy');Controller
- ルートモデルバインディングはFatControllerになる危険性があるので、使用は注意
FormRequest
- exists使う際にはdeleted_atを考慮する必要あり
- min、max、sizeなどは型指定で動きが変わるので注意
- existsの逆はuniqueを使う
public function rules() { return [ 'id' => 'required|integer|exists:posts,id,deleted_at,NULL', 'str1' => 'required|string|max:10', // 10文字以内 'str2' => 'required|string|min:10', // 10文字以上 'str3' => 'required|string|size:10', // 10文字固定 'num1' => 'required|integer|max:10', // 10以内 'num2' => 'required|integer|min:10', // 10以上 'num3' => 'required|integer|size:10', // 10固定 ]; }Eloquent
Model
- 論理削除を有効にしたい場合は
use SoftDeletes
- 全モデルでguardedにidを指定しておくと良い。予期せぬキーの登録・更新を防げる。
- created_atカラムを作成しなかった場合は
CREATED_AT = null
- updated_atカラムを作成しなかった場合は
UPDATED_AT = null
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Xxxxx extends Model { use SoftDeletes; const CREATED_AT = null; const UPDATED_AT = null; protected $guarded = [ 'id', ]; }Relation
こんなモデルがあったとして
class User extends Authenticatable { public function posts() { return $this->hasMany(Post::class); } public function comments() { return $this->hasMany(Comment::class); } }class Post extends Model { use SoftDeletes; public function user() { return $this->belongsTo(User::class); } public function comments() { return $this->hasMany(Comment::class); } }class Comment extends Model { const UPDATED_AT = null; public function user() { return $this->belongsTo(User::class); } public function post() { return $this->belongsTo(Post::class); } }リレーションメソッドでアクセスした時
- hasOneの戻り値は Model or null
- hasManyの戻り値はCollection
- belongsToの戻り値は Model or null
QueryBuilder
- クエリビルダの場合はjoinするテーブルのdeleted_atが機能しない
User::join('posts', 'users.id', '=', 'posts.user_id')->get();select * from users inner join posts on users.id = posts.user_id
- joinされるテーブルがModelの場合はdeleted_atが機能する
Post::join('comments', 'posts.id', '=', 'comments.post_id')->get();select * from posts inner join comments on posts.id = comments.post_id where posts.deleted_at is nullRelation Query
hasで流れるSQL
User::has('posts.comments')->get();[2020-12-05 23:39:48] local.DEBUG: SQL {"time":"12.82 ms","sql":"select * from `users` where exists (select * from `posts` where `users`.`id` = `posts`.`user_id` and exists (select * from `comments` where `posts`.`id` = `comments`.`post_id`) and `posts`.`deleted_at` is null)"}select * from users where exists ( select * from posts where users.id = posts.user_id and exists ( select * from comments where posts.id = comments.post_id ) and posts.deleted_at is null )joinで流れるSQL
User::join('posts', 'posts.user_id', '=', 'users.id') ->join('comments', 'comments.post_id', '=', 'posts.id') ->whereNull('posts.deleted_at') ->get();[2020-12-06 00:00:13] local.DEBUG: SQL {"time":"12.11 ms","sql":"select * from `users` inner join `posts` on `posts`.`user_id` = `users`.`id` inner join `comments` on `comments`.`post_id` = `posts`.`id` where `posts`.`deleted_at` is null"}select * from users inner join posts on posts.user_id = users.id inner join comments on comments.post_id = posts.id where posts.deleted_at is nullwithで流れるSQL
User::with('posts.comments')->get();[2020-12-05 23:49:37] local.DEBUG: SQL {"time":"11.54 ms","sql":"select * from `users`"} [2020-12-05 23:49:37] local.DEBUG: SQL {"time":"0.70 ms","sql":"select * from `posts` where `posts`.`user_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) and `posts`.`deleted_at` is null"} [2020-12-05 23:49:37] local.DEBUG: SQL {"time":"0.41 ms","sql":"select * from `comments` where `comments`.`post_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)"}select * from users select * from posts where posts.user_id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) and posts.deleted_at is null select * from comments where comments.post_id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)Console
複数時間でタスクスケジューリングしたい場合(8:30、11:30、18:30など)はcron形式にする。
app/Console/Kernel.php
->cron('30 8,11,18 * * *');コンソール出力時にログにも残す
トレイトを作成してコマンドクラスで
use PrependsOutput;
してあげればOK
普通に$this->info()
や$this->error()
するだけでログに残せます。
テスト時に実行時間を出力していない理由は、コンソール出力値もテストしているためです。app/Console/Commands/PrependsOutput.php
<?php namespace App\Console\Commands; use Carbon\CarbonImmutable; trait PrependsOutput { /** * コンソール出力に追加 * * @param string $string * @param string|null $style * @param int|string|null $verbosity * @return void */ public function line($string, $style = null, $verbosity = null) { if (\App::environment() === 'testing') { parent::line($string, $style, $verbosity); } else { parent::line(CarbonImmutable::now()->format('[Y-m-d H:i:s] ').$string, $style, $verbosity); } logger(CarbonImmutable::now()->format('[Y-m-d H:i:s] ').$string); } }PHPUnitテスト
- テストが遅い時はxdebugを無効にしてみてください。5倍くらい違う!
# テスト実行 ./vendor/bin/phpunit # 対象のファイルでテスト実行 ./vendor/bin/phpunit tests/Feature/XxxxxTest.php # 対象のファイルの対象の関数でテスト実行 ./vendor/bin/phpunit tests/Feature/XxxxxTest.php --filter=xxxxxxxx # テスト結果をログに残す ./vendor/bin/phpunit --testdox-text=test.txt他いろいろ
実行SQLを確認したい
下記を参考にしてちょっと直しました
LaravelでSQL文をlaravel.logに出力する下記をregisterに追加
app/Providers/AppServiceProvider.php
/** * Register any application services. * * @return void */ public function register() { // SQL Log \DB::listen(function ($query) { $sql = preg_replace('/"(.*?)"/', "'$1'", $query->sql); for ($i = 0; $i < count($query->bindings); $i++) { $bindValue = $query->bindings[$i]; if (is_bool($bindValue)) { $bindValue = $bindValue ? 'true' : 'false'; } else { $bindValue = "'".(string)$bindValue."'"; } $sql = preg_replace("/\?/", $bindValue, $sql, 1); } \Log::debug("SQL", ["time" => sprintf("%.2f ms", $query->time), "sql" => $sql]); }); }Laravelログ+Slackにもログを残す
- stackのchannelsにslackを追加
- slackのlevelをcritical → debugに変更
- envのLOG_SLACK_WEBHOOK_URLにslackのwebhookUrlを指定
config/logging.php
'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => [ 'single', 'slack', // 追加 ], 'ignore_exceptions' => false, ], 〜 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', 'level' => 'debug', // critical → debugに変更 ],.env
LOG_SLACK_WEBHOOK_URL=xxxxxxstackのchannelsには複数のdriverが使えるので、fatalエラーと単純なログをチャンネルごとに分けると便利です
'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => [ 'single', 'slack-critical', 'slack-debug', ], 'ignore_exceptions' => false, ], 〜 'slack-critical' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel critical Log', 'emoji' => ':boom:', 'channel' => env('LOG_SLACK_CHANNEL_ALERT'), 'level' => 'critical', ], 'slack-debug' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel debug Log', 'emoji' => ':memo:', 'channel' => env('LOG_SLACK_CHANNEL_DEBUG'), 'level' => 'debug', ],
- 投稿日:2020-11-27T14:00:25+09:00
Laravelを触って1年経ったのでTIPS
本当は2年くらいかもしれない
確認バージョンは Laravel 7.26.1
よく使うコマンド
ネームスペースとか考慮するとコマンドから作った方が良いです。でもコピペしちゃう
make系
# マイグレーション作成 php artisan make:migration create_xxxxx_table # モデル&ファクトリー&シーダー作成(app/) php artisan make:model Models/Xxxx -fs # コントローラー作成(app/Http/Controllers/) php artisan make:controller Api/XxxxController --model=Models/Xxxx --api # フォームリクエスト作成(app/Http/Requests/) php artisan make:request Api/Xxxx/Store # コマンド作成(app/Console/Commands/) php artisan make:command Xxxx ### ide-helperが導入されていれば # ide_helper:generate php artisan ide-helper:generate # ide_helper:models php artisan ide-helper:models -Ndb系
# マイグレーション実行 php artisan migrate # マイグレーションを一つ戻す php artisan migrate:rollback --step=1 # DB初期化&DatabaseSeeder実行 php artisan migrate:fresh --seed # シーダー実行 php artisan db:seed --class=UserSeederキャッシュを消す
# 全消し php artisan optimize:clear # optimize:clearの中身の実態は下記コマンド php artisan view:clear && \ php artisan cache:clear && \ php artisan route:clear && \ php artisan config:clear && \ php artisan clear-compiledちなみに間違ってもローカル開発環境で
php artisan config:cache
は使わないよう注意してください。
phpunitを走らせた際にキャッシュ化した.envの環境変数が使われてしまいます。
間違えた場合はphp artisan config:clear
してください。公式にも書いてる!
https://readouble.com/laravel/7.x/ja/configuration.htmlFactory
公式Faker
https://github.com/fzaninotto/Faker日本語ソース
https://github.com/fzaninotto/Faker/blob/master/src/Faker/Provider/ja_JP# ランダム英数字生成(unique使っても衝突してしまう場合) $faker->unique()->regexify('[a-zA-Z0-9]{1,20}')Routing
- Laravelでapiを叩いたときにjsonが返ってこない問題
php artisan route:list > route.txt
で吐き出すと楽ルーディングの書き方について
個人的にはHTTPメソッドごとにアクションを指定した方がいいかと思います。
Route::resourceを使ってデフォルトアクションを指定できるんですが、ワナがあります。
下記のように公開・下書きで投稿の処理を丸ごと分けたいなどした時に下記のようなルーティングになるかと思います。api.php
Route::resource('publish/posts', 'Publish\PostController')->only([ 'index', 'store', 'show', 'update', 'destroy', ]); Route::resource('draft/posts', 'Draft\PostController')->only([ 'index', 'store', 'show', 'update', 'destroy', ]);処理的には問題ないですが、
php artisan route:cache
(本番環境での高速化に必要)した際にname被りでエラーになります。
なのでシンプルにメソッドごとに書いた方が良いかと思います(いずれresourceで表現できないURIの方が多くなるので)Route::get('/publish/posts', 'Publish\PostController@index'); Route::post('/publish/posts', 'Publish\PostController@store'); Route::get('/publish/posts/{id}', 'Publish\PostController@show'); Route::patch('/publish/posts/{id}', 'Publish\PostController@update'); Route::delete('/publish/posts/{id}', 'Publish\PostController@destroy'); Route::get('/draft/posts', 'Draft\PostController@index'); Route::post('/draft/posts', 'Draft\PostController@store'); Route::get('/draft/posts/{id}', 'Draft\PostController@show'); Route::patch('/draft/posts/{id}', 'Draft\PostController@update'); Route::delete('/draft/posts/{id}', 'Draft\PostController@destroy');Controller
- ルートモデルバインディングはFatControllerになる危険性があるので、使用は注意
FormRequest
- exists使う際にはdeleted_atを考慮する必要あり
- min、max、sizeなどは型指定で動きが変わるので注意
- existsの逆はuniqueを使う
public function rules() { return [ 'id' => 'required|integer|exists:posts,id,deleted_at,NULL', 'str1' => 'required|string|max:10', // 10文字以内 'str2' => 'required|string|min:10', // 10文字以上 'str3' => 'required|string|size:10', // 10文字固定 'num1' => 'required|integer|max:10', // 10以内 'num2' => 'required|integer|min:10', // 10以上 'num3' => 'required|integer|size:10', // 10固定 ]; }Eloquent
Model
- 論理削除を有効にしたい場合は
use SoftDeletes
- 全モデルでguardedにidを指定しておくと良い。予期せぬキーの登録・更新を防げる。
- created_atカラムを作成しなかった場合は
CREATED_AT = null
- updated_atカラムを作成しなかった場合は
UPDATED_AT = null
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Xxxxx extends Model { use SoftDeletes; const CREATED_AT = null; const UPDATED_AT = null; protected $guarded = [ 'id', ]; }Relation
こんなモデルがあったとして
class User extends Authenticatable { public function posts() { return $this->hasMany(Post::class); } public function comments() { return $this->hasMany(Comment::class); } }class Post extends Model { use SoftDeletes; public function user() { return $this->belongsTo(User::class); } public function comments() { return $this->hasMany(Comment::class); } }class Comment extends Model { const UPDATED_AT = null; public function user() { return $this->belongsTo(User::class); } public function post() { return $this->belongsTo(Post::class); } }リレーションメソッドでアクセスした時
- hasOneの戻り値は Model or null
- hasManyの戻り値はCollection
- belongsToの戻り値は Model or null
QueryBuilder
- クエリビルダの場合はjoinするテーブルのdeleted_atが機能しない
User::join('posts', 'users.id', '=', 'posts.user_id')->get();select * from users inner join posts on users.id = posts.user_id
- joinされるテーブルがModelの場合はdeleted_atが機能する
Post::join('comments', 'posts.id', '=', 'comments.post_id')->get();select * from posts inner join comments on posts.id = comments.post_id where posts.deleted_at is nullRelation Query
- hasは1階層と2階層両方書く必要はない
- ちなみにwithは1階層と2階層両方書いても実行されるSQLは変わらない
hasで流れるSQL
User::has('posts.comments')->get();[2020-12-05 23:39:48] local.DEBUG: SQL {"time":"12.82 ms","sql":"select * from `users` where exists (select * from `posts` where `users`.`id` = `posts`.`user_id` and exists (select * from `comments` where `posts`.`id` = `comments`.`post_id`) and `posts`.`deleted_at` is null)"}select * from users where exists ( select * from posts where users.id = posts.user_id and exists ( select * from comments where posts.id = comments.post_id ) and posts.deleted_at is null )joinで流れるSQL
User::join('posts', 'posts.user_id', '=', 'users.id') ->join('comments', 'comments.post_id', '=', 'posts.id') ->whereNull('posts.deleted_at') ->get();[2020-12-06 00:00:13] local.DEBUG: SQL {"time":"12.11 ms","sql":"select * from `users` inner join `posts` on `posts`.`user_id` = `users`.`id` inner join `comments` on `comments`.`post_id` = `posts`.`id` where `posts`.`deleted_at` is null"}select * from users inner join posts on posts.user_id = users.id inner join comments on comments.post_id = posts.id where posts.deleted_at is nullwithで流れるSQL
User::with('posts.comments')->get();[2020-12-05 23:49:37] local.DEBUG: SQL {"time":"11.54 ms","sql":"select * from `users`"} [2020-12-05 23:49:37] local.DEBUG: SQL {"time":"0.70 ms","sql":"select * from `posts` where `posts`.`user_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) and `posts`.`deleted_at` is null"} [2020-12-05 23:49:37] local.DEBUG: SQL {"time":"0.41 ms","sql":"select * from `comments` where `comments`.`post_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)"}select * from users select * from posts where posts.user_id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) and posts.deleted_at is null select * from comments where comments.post_id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)Console
複数時間でタスクスケジューリングしたい場合(8:30、11:30、18:30など)はcron形式にする。
app/Console/Kernel.php
->cron('30 8,11,18 * * *');コンソール出力時にログにも残す
トレイトを作成してコマンドクラスで
use PrependsOutput;
してあげればOK
普通に$this->info()
や$this->error()
するだけでログに残せます。
テスト時に実行時間を出力していない理由は、コンソール出力値もテストしているためです。app/Console/Commands/PrependsOutput.php
<?php namespace App\Console\Commands; use Carbon\CarbonImmutable; trait PrependsOutput { /** * コンソール出力に追加 * * @param string $string * @param string|null $style * @param int|string|null $verbosity * @return void */ public function line($string, $style = null, $verbosity = null) { if (\App::environment() === 'testing') { parent::line($string, $style, $verbosity); } else { parent::line(CarbonImmutable::now()->format('[Y-m-d H:i:s] ').$string, $style, $verbosity); } logger(CarbonImmutable::now()->format('[Y-m-d H:i:s] ').$string); } }PHPUnitテスト
- テストが遅い時はxdebugを無効にしてみてください。5倍くらい違う!
# テスト実行 ./vendor/bin/phpunit # 対象のファイルでテスト実行 ./vendor/bin/phpunit tests/Feature/XxxxxTest.php # 対象のファイルの対象の関数でテスト実行 ./vendor/bin/phpunit tests/Feature/XxxxxTest.php --filter=xxxxxxxx # テスト結果をログに残す ./vendor/bin/phpunit --testdox-text=test.txt他いろいろ
実行SQLを確認したい
下記を参考にしてちょっと直しました
LaravelでSQL文をlaravel.logに出力する下記をregisterに追加
app/Providers/AppServiceProvider.php
/** * Register any application services. * * @return void */ public function register() { // SQL Log \DB::listen(function ($query) { $sql = preg_replace('/"(.*?)"/', "'$1'", $query->sql); for ($i = 0; $i < count($query->bindings); $i++) { $bindValue = $query->bindings[$i]; if (is_bool($bindValue)) { $bindValue = $bindValue ? 'true' : 'false'; } else { $bindValue = "'".(string)$bindValue."'"; } $sql = preg_replace("/\?/", $bindValue, $sql, 1); } \Log::debug("SQL", ["time" => sprintf("%.2f ms", $query->time), "sql" => $sql]); }); }Laravelログ+Slackにもログを残す
- stackのchannelsにslackを追加
- slackのlevelをcritical → debugに変更
- envのLOG_SLACK_WEBHOOK_URLにslackのwebhookUrlを指定
config/logging.php
'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => [ 'single', 'slack', // 追加 ], 'ignore_exceptions' => false, ], 〜 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', 'level' => 'debug', // critical → debugに変更 ],.env
LOG_SLACK_WEBHOOK_URL=xxxxxxstackのchannelsには複数のdriverが使えるので、fatalエラーと単純なログをチャンネルごとに分けると便利です
'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => [ 'single', 'slack-critical', 'slack-debug', ], 'ignore_exceptions' => false, ], 〜 'slack-critical' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel critical Log', 'emoji' => ':boom:', 'channel' => env('LOG_SLACK_CHANNEL_ALERT'), 'level' => 'critical', ], 'slack-debug' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel debug Log', 'emoji' => ':memo:', 'channel' => env('LOG_SLACK_CHANNEL_DEBUG'), 'level' => 'debug', ],
- 投稿日:2020-11-27T11:55:43+09:00
Laravel 7 Socialiteを使ってLINE認証を実装してみる。
はじめに
Laravel7でLINE認証機能を実装しました。
記事自体はポチポチあるけど、古い記事が多いしやり方も色々あってなんかうまくいかない...。
少し手間取りましたが、無事実装できたので備忘録として纏めます。偉大な参考記事
ほとんど下記URLの作成者様のコーディングを参考にして書いております。
https://tdomy.com/2020/08/how-to-use-laravel-socialite/上記記事に加えてLINEのDevelopersの詳細等を補足して説明します。
上記記事ではLaravel6っぽいです。
私のはLaravel7でやってみます。実装環境
・XAMPP
・Windows10
・PHP 7.4.11
・Laravel 7.31LINE Developersで諸々登録
まずLINE Developersに登録してアプリで使うidやらなんやらを取得します。
登録したら早速プロバイダーを作成してみましょう。名前は何でもオッケーです。
そしたらLINEログインチャンネルを作成しましょう。
チャネル作成の画面でチャネル名だのなんだのを設定できます。
ここでの名前は自分の覚えやすい名前等で登録します。・チャネルタイプはLINE Loginを選択
・アプリの種類は該当のものにチェック
その他は埋めるところは埋めましょう。チャネルを作成できたら上記画面のようになります。
このページでチャネルIDとチャネルシークレットは後々使用します。
ここのLINEログインをクリックしてコールバックURLを設定しましょう。
URLはhttps://localhost/アプリ名/public/login/line/callback みたいな感じで。それでは次はログインで使用するLINEアカウントに権限をつけましょう。
LINE Developersで登録したアカウントを今回ログインで使用するものと同じであればやらなくておkです。
ビジネスアカウントとかで登録している場合は下記をしないとエラーになるのでやりましょう。これで準備オッケー!
それではLaravelに移りましょー。Socialiteを導入
Laravelのcreateからauthの導入は省きます。
それでは下記コマンドでsocialiteを入れましょう。$composer require laravel/socialiteこれでfacebookやgoogleとかは使えるのですが、
残念ながらLINEは対象外...。
ということで追加でLINE専用プロパイダーを入れましょう。$ composer require socialiteproviders/lineこれでプロパイダーはオッケー。次は環境変数ですね。
環境変数を入れる
先ほどLINE Developersで取得したIDだのを記載します。
config/service.php'line' => [ 'client_id' => env('LINE_CLIENT_ID'), 'client_secret' => env('LINE_CLIENT_SECRET'), 'redirect' => env('LINE_CLIENT_CALLBACK'), ],.envLINE_CLIENT_ID=ここにclientIDを入れる LINE_CLIENT_SECRET=ここにシークレットIDを入れる LINE_CLIENT_CALLBACK=/login/line/callbackこんな感じでオッケーです。
プロパイダー追加の記述
LINEのように別途でプロパイダーを追加した場合は下記の記述をします。
config/app.php'providers' => [ // デフォルトでいろいろ書かれてます SocialiteProviders\Manager\ServiceProvider::class, // ここを追記 ];もういっちょ
app/Providers/EventServiceProvider.phpprotected $listen = [ // デフォルトでなんかいろいろ書かれてる \SocialiteProviders\Manager\SocialiteWasCalled::class => [ 'SocialiteProviders\\Line\\LineExtendSocialite@handle', //ここの二行を追記 ], ];よっしゃこれでSocialiteを使う準備オッケー!
Usersテーブルを変更する
LaravelではデフォルトでUsersテーブルがありますが、
今回のユーザー新規登録ではname,provider,provided_user_idで登録させるとします。migrations/2014_10_12_000000_create_users_table.php<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->enum('provider', ['line', 'twitter']); $table->string('provided_user_id'); $table->timestamps(); $table->unique(['provider', 'provided_user_id']); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } }編集し終えたら忘れずにmigrateします。
Userモデルを実装
Userモデルもデフォルトであるのでそれを使います。
app/User.php<?php namespace App; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; use Illuminate\Auth\Authenticatable; class User extends Model implements AuthenticatableContract { use Authenticatable, Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'provider', 'provided_user_id', ]; /** * Get the password for the user. * * @return string */ public function getAuthPassword() { // We don't use password login. return ''; } /** * Get the column name for the "remember me" token. * * @return string */ public function getRememberTokenName() { // We don't use this. return ''; } }これでモデルもオッケーです。
次はコントローラー記述です。コントローラー実装
Authを作ったときに自動でLoginControllerが作られるのでそれを使います。
app/Http/Controllers/Auth/LoginController.php<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Providers\RouteServiceProvider; use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Support\Facades\Auth; //追記 use Laravel\Socialite\Facades\Socialite; //追記 use App\User; //追記 class LoginController extends Controller { /* |-------------------------------------------------------------------------- | Login Controller |-------------------------------------------------------------------------- | | This controller handles authenticating users for the application and | redirecting them to your home screen. The controller uses a trait | to conveniently provide its functionality to your applications. | */ use AuthenticatesUsers; /** * Where to redirect users after login. * * @var string */ protected $redirectTo = RouteServiceProvider::HOME; /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('guest')->except('logout'); } /**ここから下が追記 */ /** * Redirect the user to the provider authentication page. * * @param string $provider * @return \Illuminate\Http\Response */ public function redirectToProvider($provider) { return Socialite::driver($provider)->redirect(); } /** * Obtain the user information from the provider. * * @param string $provider * @return \Illuminate\Http\Response */ public function handleProviderCallback($provider) { $provided_user = Socialite::driver($provider)->user(); $user = User::where('provider', $provider) ->where('provided_user_id', $provided_user->id) ->first(); if ($user === null) { // redirect confirm $user = User::create([ 'name' => $provided_user->name, 'provider' => $provider, 'provided_user_id' => $provided_user->id, ]); } Auth::login($user); return redirect()->route('home'); } /** * Log the user out of the application. * * @return \Illuminate\Http\Response */ public function logout() { Auth::logout(); return redirect()->route('home'); } }return redirect先のパスは各自好きなrouteを指定してください。
今回はデフォルトでルート付けされているhome
にしています。ルーティングを作る
さて、最後にloginとlogoutに関するルーティングをして終わりです!
routes/web.php<?php use Illuminate\Support\Facades\Route; /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::get('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/home', 'HomeController@index')->name('home'); Route::get('/login/{provider}', 'Auth\LoginController@redirectToProvider'); Route::get('/login/{provider}/callback', 'Auth\LoginController@handleProviderCallback'); Route::get('/logout', 'Auth\LoginController@logout')->name('logout');これでルート付けもできた!ということでLineログインまで飛んでみましょう。
今回はURLで飛んでみます。
https://locallhost/アプリ名/public/login/line で飛んでみると....。ここでメアドとパスワードを入れてみる。
You are logged in!!!!!!!!!!!!!!!!!
やったー!ログインできた!ついでにMySQLを見るとしっかりidが追加されてました!感想
Laravel7の記事がとても少ないし、LINEのプロパイダー記事も古い記事が多く割と躓きました。
参考記事の方はlaravel6だったのですが、同じ方法で7もできました。
他のプロパイダーを追加した場合の記事も完成次第投稿したいと思います。
- 投稿日:2020-11-27T11:38:37+09:00
意地でもvimでコード補完したい人へ
まだvimの補完で消耗してんの?
PHPStorm便利だよねえっていうツイートをみるといつも羨ましいvim使いです。
そりゃねえお金あったらPHPStormとか使いますよ。そうだ!そうだ!お金で解決しよう(社長よろしく)でも生来のvim使いなのにそんな文明の利器に負けていいのか、そう自問自答して何年たったのだろう。そうVisualStudioCodeを見ながら・・・!
TL;DR
- coc.vimをつかえ
設定はほとんど公式サイトのそのままで問題ない。インストールにハマることはなかった。動作はとても快適。
https://github.com/neoclide/coc.nvim
思えばvimでのコード補完の道のりは長く険しいものでした
vim使いの人はご存知かもしれませんが、私も例に漏れずneocomplete / deopleteなどなどと共に歩んで来ました。ところがvimのバージョンが上がるたびに何故か動かない、設定がうまくできない。
私のvimスキル不足とういうのも大いにあるのでしょうが、いつも勢いでmac osアップデートして死ぬとかbrew upgradeとかして動かないbuglist見るとかして苦労していました。
どうしてもvimそのものにこだわる私としてはneovimやmacvimへの移行は絶対にしない(でも補完動かないのでモヤモヤが募る・・・)
そこで見つけたcoc.vim
LSPでvim補完しちゃう
LSPとはMicrosoftがつくって公開したプロトコル。VSCodeでもつかってる(から補完とかできるわけです)。詳しくは他の人がめちゃくちゃちゃんと書いてくれてます。(Qiitaの民はいつも感心させられる)
https://qiita.com/atsushieno/items/ce31df9bd88e98eec5c4
こまけえことはいいんだよ、インストール方法は?
https://github.com/neoclide/coc.nvim/wiki/Install-coc.nvim
phpの人は
:CocInstall coc-phplsだけでいける。特に何かを設定しないといけないとかはない。公式サイトに書いてあるとおりにやれば十分に動くと思う。
ちゃんと動いてるかの確認は
vimで拡張子がターゲットのものに関して、入力すると補完のポップアップがでてくるので候補の横に[LS]と出てればOKです。
- 投稿日:2020-11-27T01:04:07+09:00
switch文[PHP]
switch文をPHPで書く
if, elseifによる分岐が多く複雑な場合、switch文で書き換えるとシンプルで読みやすいコードにできる。switch(式)の(式)がcaseの値と一致したとき、そのブロックが実行される。caseのどれにも一致しなかった時、defaultのブロックが実行される
break
break命令は現在のブロックから脱出するための命令。break命令がないと、後ろに続くcaseブロックが続けて実行されてしまう
switch($remainder) { case 0: echo "大吉です。"; break; case 1: echo "中吉です。"; break; case 2: echo "小吉です。"; break; default: echo "凶です。"; break; }以上!
- 投稿日:2020-11-27T00:12:11+09:00
Xdebug3.0.0がリリースされたので、ver2からの雑なコンバート
Xdebug 3.0.0 is out!
11/25にXdebug 3.0.0 is out!されたわけですが、
pecl install xdebug
と記載していて、まんまと勝手にver3がインストールされてしまい、まんまと以前の設定で動かず焦っている今日この頃ですが皆さんいかがお過ごしでしょうか?そんなわけで、私が使用している設定をコンバートし、ひとまず変更を加えて動くところまで雑にやって、雑にまとめました。
mode設定
ver2.x系でとりあえずステップデバッグを使うためには、下記の設定を行っていたと思います。いや、むしろこれがほぼすべてと言ってもよいくらい。
xdebug.remote_enable=1 xdebug.default_enable=0 xdebug.profiler_enable=0 xdebug.auto_trace=0 xdebug.coverage_enable=0ver3.x系では
xdebug.mode=debugとなります。
modeにいくつかの設定が集約されたようで、そのvalueの記載でフラグを管理していく感じです。
以前の設定とmodeのvalueのコンバートはこう。
以前の設定 modeのvalue default_enable develop profiler_enable profile remote_enable debug 同時に設定したい場合はvalueをカンマ区切り。
xdebug.mode=develop,debugその他コンバートが必要だったもの
xdebug.remote_autostartを設定する場合、下記の2つを設定するようです。
- xdebug.mode=debug
- xdebug.start_with_request=yes.
だいたいの人が必要そうな設定はこちらです。
以前の設定 新しい設定 profiler_output_dir output_dir remote_host client_host remote_port client_port output_dir系はoutput_dirにまとめられたっぽいです。
ここまでの設定でブレークポイントまでは動かすことができました。
ポート番号
私はポートを指定していたので引っかからなかったのですが、デフォルトのポート番号が
9003
へ変更になっています。参考
参考にしたのは公式ドキュメント。
結局、必要な設定を検索しながらポチポチ地道に書き換えていくしかなさそうです。動いたini
最期にXdebugが動作したiniを記載しておきます。
開発環境はPhpStormで、Dockerサーバーです。xdebug.idekey=PHPSTORM xdebug.client_host=host.docker.internal xdebug.client_port=9010 xdebug.idekey=PHPSTORM xdebug.mode=debug,develop