- 投稿日:2020-03-23T20:42:48+09:00
【PHP8.0】gettypeとget_classの悪魔合体
ワレハget_debug_type、コンゴトモヨロシク…
PHPにはプリミティブ型名を取得するgettypeと、オブジェクトのクラス名を返すget_classという関数が存在します。
_
があったりなかったりと命名の不統一も気になりますが、それよりgettypeはオブジェクトに使うとobject
しか返さず、get_classをプリミティブ型に使うとE_WARNINGが発生します。
いや、プリミティブ型であればint
とかの型が欲しいし、オブジェクトならPDO
とかの型が欲しいんだ、という問題に対する答えはありませんでした。というわけで両者を合体させたget_debug_typeというRFCが提出されました。
PHP RFC: get_debug_type
proposal
このRFCは、指定された変数の型を返す新しい関数、
get_debug_type
を追加する提案です。これは、配列で来る値など、変数の型に基づいた既存のチェック方法では対応できないパターンを置き換えるためのものです。
$bar = $arr['key']; if (!($bar instanceof Foo)) { // もっとも単純な例。しかしgettypeは"integer"を返すので、正しい型にしたいなら"int"に変換するなどが必要。 throw new TypeError('Expected ' . Foo::class . ' got ' . (is_object($bar) ? get_class($bar) : gettype($bar))); } // 今後はこう書ける if (!($bar instanceof Foo)) { throw new TypeError('Expected ' . Foo::class . ' got ' . get_debug_type($bar)); } $bar->someFooMethod();この関数は、正しい型名を返すという点でgettypeと異なります。
"integer"ではなく"int"を返し、クラスもクラス名に変換します。
次の表は、いくつかの値に対してgettype
とget_debug_type
が返す値を比較したものです。
値 get_debug_type() gettype() 0 int integer 0.1 float double true bool boolean false bool boolean "hello" string [] array null null NULL Foo\Bar Foo\Bar object 無名クラス class@anonymous object リソース resource (xxx) resource 閉じたリソース resource (closed) Backward Incompatible Changes
なし。
Proposed PHP Version(s)
PHP8.0
Implementation
https://github.com/php/php-src/pull/5143
投票
投票は2020/03/26まで、2/3の賛成で受理されます。
このRFCは賛成42、反対3で受理されました。感想
Mark Randallは最初はgettypeがクラス名も返すようにしようとしたものの、Nikitaから「新しい関数にしてくれ」と言われてget_debug_typeを作ったようです。
まあ、これまでobject
としか言わなかったgettypeがいきなり色々な型を喋り出したら困るところも出そうですからね。ということで、今後は型の取得は
get_debug_type
に一本化できそうです。手間を省くための定型処理を言語機能に取り込むことは、他の言語でも多々起きていることです。
たとえばJavaScriptのasync/await
はPromise
の糖衣にすぎず、async/await
ができることは全てPromise
でもできるので、究極的にはasync/await
は不要です。
しかし非同期処理を楽に書けるようにするために言語仕様に取り込まれました。
糖衣構文の取り込み自体は、このようにさほど珍しいことでもありません。しかし、str_containsとかis_countableとか、他言語であれば「自分で書け」と言われそうな極端に簡単な構文まで言語仕様に取り込んでしまう言語は、PHP以外にはそうそう無いのいではないかと思います。
- 投稿日:2020-03-23T19:31:27+09:00
Laravelのライブラリ「laravel-dompdf」を使ってビューの表示をPDFとして表示しよう
目的
- ライブラリを使用して現在のビューとして表示しているコードをそのままPDFで表示する方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.3) ハードウェア MacBook Air (11-inch ,2012) プロセッサ 1.7 GHz デュアルコアIntel Core i5 メモリ 8 GB 1600 MHz DDR3 グラフィックス Intel HD Graphics 4000 1536 MB
- ソフトウェア環境
項目 情報 PHP バージョン 7.4.3 Laravel バージョン 7.0.8 実施条件
- 下記の記事に沿って環境構築を行っていること。
- ローカル開発環境でブラウザから確認可能なLaravelアプリがあること。
実施方法概要
- コントローラの確認
- アクションの記載変更
- 確認
実施方法詳細
コントローラの確認
PDFとして表示したいビューファイルが呼び出されているコントローラファイルを表示する。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; ・ ・ ・
use Illuminate\Http\Request;
の下に下記の内容を記載する。use PDF;コントローラファイルの設定部分が下記の様になっていることを確認する。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use PDF; ・ ・ ・アクションの記載変更
先に確認したコントローラファイルのビューを表示しているアクションを確認する。
return view('ビューファイルディレクトリ名.ビューファイル名');先に確認した
return
部分を下記の様に記載する。$pdf = PDF::loadView('ビューファイルディレクトリ名.ビューファイル名'); return $pdf->stream();確認
下記コマンドを実行してローカルサーバを起動する。
$ cd アプリ名ディレクトリ $ php artisan serve修正したアクションとリンクするURLにアクセスする。
PDFで表示されればOKである。(日本語は文字化け表示されるが、現在の設定だと正常である。)
- 投稿日:2020-03-23T18:53:24+09:00
【WordPress】カスタムブロックの作り方を書いてみた
はじめに
WordPress 5.0からGutenbergと呼ばれるブロックエディターがデフォルトのエディターとして採用されました。
そのため、今後はこのブロックエディターによる開発が増えてくると思われます。個人的には、今までのWysiWygエディターに不満を感じていたわけではありませんが、ブロックエディターという選択肢が増えたことで、できる事の幅が増えてくる と思います。
本記事では、このブロックエディターの新規ブロック(以降、カスタムブロック)の作り方を記載して行きます。ブロックエディターとは?
ブロックエディターは、名前の通り、HTMLをブロックように積み上げてHTMLを作成していくエディターです。
詳細は、以下を参照ください。
https://ja.wordpress.org/gutenberg/
ブロックエディターの特徴の1つとして、上記リンク先のページにも記載がありますが、 実際のサイトと同様に表示されるエディター。 であることです。
これから記載するカスタムブロックも、実際のサイトと同様に表示されるよう作成して行きます。また、WordPressのブロックエディターは、大きく分けて以下の2種類のカスタムブロックを作成できます。
- 動的ブロック ・・・ 最新の投稿を表示するブロック等の動的にブロックの内容が変化するブロック
- 静的ブロック ・・・ 動的とは反対で、画像アップロードやテキストフィールド等のブロックの内容が変化しないブロック
これから記載するカスタムブロックは静的ブロックを作成して行きます。(動的ブロックは別途記載予定)
作成するカスタムブロック
以下のようなテキストが書けて、背景色をサイドナビゲーションから選択できるカスタムブロックを作成して行きます。
サンプルブロックは、エディターと画面表示(以降、フロント)にCSSが適応されるブロックと、エディターのみCSSが適応されるブロックの2種類作成します。環境準備
以下がインストールされている事が前提です。
- PHP: 7.1以上
- Node: v10.x
- Yarn: v1.9.4
WordPressのブロックエディターはReactで作成されています。
これから作成するカスタムブロックも、ReactのComponentを使って開発して行きます。
しかし、通常のReactを使用するのではなく、WordPress側で用意されているReactを使用します。そのため、Reactをインストールする必要はありません。以降、ライブラリのインストールです。
[必須]package.jsonを用意する
以下のような
package.json
を作成します。{ "name": "sample-block", "version": "1.0.0", "description": "Sample Block", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Kodak", "license": "GPL-2.0" }[任意]webpackを用意する
こちらは任意です。
JavaScriptをwebpackを通してビルドしたい方は、以下をインストールしてください。
今回は、後述する@wordpress/scripts
を使ってビルドをするので、インストールしません。yarn add -D webpack webpack-cli[必須]BABELを用意する
以下をインストールします。
カスタムブロックはJSXを使いたいので@babel/preset-react
もインストールします。yarn add -D @babel/core babel-loader @babel/preset-env @babel/preset-react
@babel/core
・・・ BABEL本体babel-loader
・・・ webpackからBABELを通すためのライブラリ@babel/preset-env
・・・ 特定の環境(ブラウザ)に合わせた変換をしてくれるライブラリ@babel/preset-react
・・・ JSXのコンパイル可能にするライブラリ[任意]SASSに対応させるためのライブラリを用意する
こちらは任意です。
今回はSASSに対応させたいため、以下をインストールします。yarn add -D node-sass css-loader sass-loader
node-sass
・・・ SASS(SCSS)をCSSに変換するライブラリsass-loader
・・・ webpackからSASS(SCSS)をCSSに変換するライブラリcss-loader
・・・ CSSをJavaScriptにバンドルするライブラリ[任意]CSSを拡張するためのライブラリを用意する
こちらは任意ですが、インストールしておいたほうが良いです。
ベンダープレフィックスやCSSを別ファイルとして出力してくれます。yarn add -D postcss-loader autoprefixer mini-css-extract-plugin optimize-css-assets-webpack-plugin terser-webpack-plugin
postcss-loader
・・・ ベンダープレフィックスをCSSに追加するため&ネストしたCSSを解析してくれるライブラリautoprefixer
・・・ ベンダープレフィックスをCSSに追加(postcss-loader
のプラグイン)mini-css-extract-plugin
・・・ CSSを別ファイルとして出力するためのライブラリoptimize-css-assets-webpack-plugin
・・・ 作成するCSSを圧縮するためのライブラリterser-webpack-plugin
・・・ CSSを圧縮する際、さらにCSSを縮小してくれる(邪魔なコメントやscourceMapを削除してくれる)ライブラリ[必須]ビルドフォルダーにゴミファイルを残さないためのライブラリを用意する
ビルドフォルダーにゴミファイルを残さないようにするため、これはインストールしておきましょう。
yarn add -D clean-webpack-plugin
clean-webpack-plugin
・・・ ビルドする度に、ビルドフォルダーを削除するライブラリ[必須]カスタムブロックを作るライブラリを用意する
カスタムブロックを作成するためのライブラリです。
yarn add -D @wordpress/browserslist-config @wordpress/scripts @wordpress/blocks @wordpress/dependency-extraction-webpack-plugin
@wordpress/browserslist-config
・・・ WordPressのブロックエディターが動くブラウザリストのライブラリ@wordpress/scripts
・・・ WordPressのブロックエディター用のwebpackが詰め込まれたライブラリ。これを使用しない場合は、webpackを別途インストールする必要がある。@wordpress/blocks
・・・ WordPressでカスタムブロックを作るためのライブラリ。@wordpress/dependency-extraction-webpack-plugin
・・・ ライブラリの依存関係を自動で解決するassets.phpファイルを生成してくれるライブラリ[任意]作成するカスタムブロックに合わせてライブラリを用意する
作りたいカスタムブロックに合わせて、ライブラリをインストールします。
今回は、@wordpress/block-editor
と@wordpress/components
を使用します。yarn add -D @wordpress/block-editor @wordpress/components各ライブラリの詳細は、公式サイトを参照してください。
https://developer.wordpress.org/block-editor/packages/
事前準備
package.json(折りたたんでいます)
{ "name": "sample-block", "version": "1.0.0", "description": "Sample Block", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "wp-scripts build --mode=development --config webpack.config.js --watch", "build": "wp-scripts build --mode=production --config webpack.config.js" }, "author": "Kodak", "license": "GPL-2.0", "devDependencies": { "@babel/core": "^7.8.7", "@babel/preset-env": "^7.8.7", "@babel/preset-react": "^7.8.3", "@wordpress/block-editor": "^3.7.5", "@wordpress/blocks": "^6.12.1", "@wordpress/browserslist-config": "^2.6.0", "@wordpress/components": "^9.2.4", "@wordpress/dependency-extraction-webpack-plugin": "^2.4.0", "@wordpress/scripts": "^7.1.3", "autoprefixer": "^9.7.4", "babel-loader": "^8.0.6", "clean-webpack-plugin": "^3.0.0", "css-loader": "^3.4.2", "mini-css-extract-plugin": "0.6.0", "node-sass": "^4.13.1", "optimize-css-assets-webpack-plugin": "^5.0.3", "postcss-loader": "^3.0.0", "sass-loader": "^8.0.2", "terser-webpack-plugin": "^2.3.5" }, "browserslist": [ "extends @wordpress/browserslist-config" ] }WordPress用のwebpack(wp-scripts)を使用して、ビルドをするため、以下のように定義します。
"scripts": { "start": "wp-scripts build --mode=development --config webpack.config.js --watch", "build": "wp-scripts build --mode=production --config webpack.config.js" },ブラウザリストはextendsを使用して読み込みます。
"browserslist": [ "extends @wordpress/browserslist-config" ]注)mini-css-extract-pluginは、chunkFilenameを使用しているとエラーが出たのでバージョンを0.6.0にしています。
webpack.config.js(折りたたんでいます)
const autoprefixer = require('autoprefixer'); const MiniCSSExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCSSAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); const TerserWebpackPlugin = require('terser-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const DependencyExtractionWebpackPlugin = require('@wordpress/dependency-extraction-webpack-plugin'); module.exports = (env, argv) => { // mode('development'と'production')によって動作を切り替える関数 function isDevelopment() { return argv.mode === 'development' } var config = { entry: { editor: './src/editor.js', script: './src/script.js', }, output: { filename: "[name].js" }, optimization: { minimizer: [ // sourceMapをmodeによって削除する new TerserWebpackPlugin({ sourceMap: isDevelopment() }), // CSSを圧縮する new OptimizeCSSAssetsWebpackPlugin( { cssProcessorOptions: { map: { inline: false, annotation: true } } } ) ] }, plugins: [ // assets.phpファイルを出力する new DependencyExtractionWebpackPlugin(), // ビルドの度にビルドフォルダーを削除する new CleanWebpackPlugin(), // CSSファイルを別ファイルで出力する new MiniCSSExtractPlugin({ chunkFilename: "[id].css", filename: chunkData => { return chunkData.chunk.name === "script" ? 'style.css' : '[name].css'; } }) ], // source-mapを使用する devtool: 'source-map', module: { rules: [ { // JavaScriptのローダーの設定 test: /\.js$/, exclude: /node_modules/, use: { // BABELを使用する loader: 'babel-loader', options: { presets: [ '@babel/preset-env', [ '@babel/preset-react', { // Reactで使用する関数をBABELをトランスパイルします // 通常は"React.createElement.xxxx"を記述しますが、WordPressのブロックエディターはWordPress用のReactを使用するため、以下のように記述します "pragma": "wp.element.createElement", "pragmaFrag": "wp.element.Fragment", "development": isDevelopment() } ] ] } } }, { // SASSのローダーの設定 test: /\.(sa|sc|c)ss$/, use: [ // CSSを別ファイル化するためのローダーを指定 MiniCSSExtractPlugin.loader, 'css-loader', { // postcss-loaderのプラグインを使って、ベンダープレフィックスをCSSに追加 loader: 'postcss-loader', options: { plugins: [ autoprefixer() ] } }, 'sass-loader' ] } ] }, }; return config; }Reactで使用する関数をBABELをトランスパイルします。
通常は"React.createElement.xxxx"を記述しますが、WordPressのブロックエディターはWordPress用のReactを使用するため、以下のように記述します。'@babel/preset-react', { "pragma": "wp.element.createElement", "pragmaFrag": "wp.element.Fragment", }WordPress用のwebpack(wp-scripts、dependency-extraction-webpack-plugin)を使用して、ビルドをしない方は、WordPressの依存関係を解決するために以下のような記述が必要なので注意してください。
ご参考)https://developer.wordpress.org/block-editor/packages/packages-dependency-extraction-webpack-plugin/
externals: { "@wordpress/blocks": ["wp", "blocks"], "@wordpress/editor": ["wp", "editor"], "@wordpress/components": ["wp", "components"], "@wordpress/element": ["wp", "element"], }プラグインとしてカスタムブロックを開発
カスタムブロックを作成する流れを図にすると以下のような感じです。
どこから作成しても問題ありませんが、カスタムブロックJSメインコードとカスタムブロックスタイルコードを作成して、最後にカスタムブロック登録コードを作るのが良いと思います。
firstblock/editor.js(折りたたんでいます)
import './editor.scss'; import { registerBlockType } from "@wordpress/blocks"; import { RichText, InspectorControls } from "@wordpress/editor"; import { PanelBody, ColorPalette } from "@wordpress/components"; registerBlockType('sample-block/firstblock', { title: 'サンプルブロック(editor)', icon: 'wordpress-alt', category: 'common', example: {}, attributes: { content: { type: 'string', source: 'html', selector: 'p' }, colorPrefix: { type: 'string', default: '' } }, edit( { className, attributes, setAttributes } ) { const { content, colorPrefix } = attributes; const changeBackGroundColor = (backGroundColor) => { let color_prefix = ''; switch ( backGroundColor ) { case 'blue': color_prefix = '--blue' ; break; case 'red': color_prefix = '--red'; break; case 'green': color_prefix = '--green'; break; case 'yellow': color_prefix = '--yellow'; break; default: color_prefix = ''; break; } setAttributes({colorPrefix: color_prefix}) } return ( <div className={ className }> <InspectorControls> <PanelBody title='背景カラー設定'> <ColorPalette colors={[ {name: 'ブルー', color: 'blue'}, {name: 'レッド', color: 'red'}, {name: 'グリーン', color: 'green'}, {name: 'イエロー', color: 'yellow'}, ]} disableCustomColors='true' onChange={ changeBackGroundColor } /> </PanelBody> </InspectorControls> <RichText className={`wp-block-sample-block-firstblock__content${colorPrefix}`} tagName='p' onChange={ ( content ) => setAttributes( { content: content } ) } value={ content } /> </div> ); }, save( { attributes } ) { const { content, colorPrefix } = attributes; return ( <div> { content && ( <RichText.Content className={`wp-block-sample-block-firstblock__content${colorPrefix}`} tagName='p' value={ content } /> )} </div> ); } });
firstblock/editor.scss(折りたたんでいます)
.wp-block-sample-block-firstblock { &__content { color: black; background-color: white; } &__content--red { color: white; background-color: red; } &__content--green { color: white; background-color: green; } &__content--blue { color: white; background-color: blue; } &__content--yellow { color: red; background-color: yellow; } }
edit
関数がエディター表示の部分、save
関数がフロントを表示する部分になります。
attributes
は、主にエディターで設定した値(edit
関数で設定した値)をフロントへ渡す値(save
関数へ渡す値)を定義します。
上記だと、RichText書かれたValue値やColorPaletteで選択したクラス名のプレフィックスなどです。サイドナビゲーションは、InspectorControls、PanelBodyなどを組み合わせれば簡単に実装できます。
plugin.php(折りたたんでいます)
<?php /** * Plugin Name: Sample-Block * Plugin URI: * * Description: Sample用カスタムブロック. * Version: 1.0 * Author: Kodak * Author URI: * * License: GPL2 * * @package sample-block */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * カスタムブロックの登録. */ function sample_block_register() { // スクリプトファイルをWordPressに登録する. $editor_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/editor.asset.php' ); $script_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/script.asset.php' ); // editor-script用のJSファイル. wp_register_script( 'sample-block-editor-script', plugins_url( 'dist/editor.js', __FILE__ ), $editor_asset_file['dependencies'], $editor_asset_file['version'] ); // editor-style用のCSSファイル. wp_register_style( 'sample-block-editor-style', plugins_url( 'dist/editor.css', __FILE__ ), [ 'wp-edit-blocks' ], filemtime( plugin_dir_path( __FILE__ ) . 'dist/editor.css' ) ); // script用のJSファイル. wp_register_script( 'sample-block-script', plugins_url( 'dist/script.js', __FILE__ ), $script_asset_file['dependencies'], $script_asset_file['version'] ); // style用のCSSファイル. wp_register_style( 'sample-block-style', plugins_url( 'dist/style.css', __FILE__ ), [ 'wp-edit-blocks' ], filemtime( plugin_dir_path( __FILE__ ) . 'dist/style.css' ) ); // カスタムブロックの登録(editor). register_block_type( 'sample-block/firstblock', [ 'editor_script' => 'sample-block-editor-script', // エディター画面の時のみスクリプトを読み込む. 'editor_style' => 'sample-block-editor-style', // エディター画面の時のみスタイルを読み込む. ] ); // カスタムブロックの登録. register_block_type( 'sample-block/secondblock', [ 'script' => 'sample-block-script', // エディター・フロントの両画面でスクリプトを読み込む. 'style' => 'sample-block-style', // エディター・フロントの両画面でスタイルを読み込む. ] ); } add_action( 'enqueue_block_editor_assets', 'sample_block_register' ); add_action( 'enqueue_block_assets', 'sample_block_register', 1 );WordPress用のwebpack(wp-scripts、dependency-extraction-webpack-plugin)を使用して、ビルドした場合、スクリプトファイル(xxxx.asset.php)が作られます。
ライブラリの依存関係やバージョン情報が書かれているので、それらを使ってJSファイルを登録します。カスタムブロックの登録は、
editor_script
、editor_style
、script
、style
の4種類があります。
4つの違いは以下の通りです。
editor_script
・・・ エディター画面の時のみスクリプトを読み込むeditor_style
・・・ エディター画面の時のみスタイルを読み込むscript
・・・ エディター・フロントの両画面でスクリプトを読み込むstyle
・・・ エディター・フロントの両画面でスタイルを読み込む例えば、本記事の最初に見せたブロックをプレビューしてフロントから見てみると以下のように表示されます。
上:エディターとフロントにCSSが適応されるブロック(
script
、style
)を使用した場合
下:エディターのみCSSが適応されるブロック(editor_script
、editor_style
)を使用した場合上の方は、エディターで指定した背景色(赤色)がフロントに適用されていることがわかります。
対して、下の方はエディターで指定した背景色(緑色)がフロントには反映されていないことがわかります。最後にHookですが、
editor_script
、editor_style
を使用する場合はenqueue_block_editor_assets
を使いましょう。
script
、style
を使用する場合はenqueue_block_assets
を使いましょう。
ちゃんとブロックエディター用のHookが用意されているので、適切なHookを使用するようにしましょう。間違ってもinit
は使用しないようにしましょう。さいごに
というわけで、長々とカスタムブロックの作り方を書いてみましたが、いかがだったでしょうか。
個人的に一番苦労したのはwebpackの設定です。
私自身バックエンドのエンジニアなので、webpackの設定方法を理解するのにえらい時間が掛かりました・・・
カスタムブロックはモダンな作りになっていて面白いのですが、学習コストが高いのが辛いところですね。今度は、動的ブロックの作成にも挑戦したいと思います。
- 投稿日:2020-03-23T18:24:58+09:00
tailコマンド メモ
PHP側のログを追うことになったのでメモ(FuelPhp以外だとよくわからん)
▼追記されるログを表示
tail -f ファイル名
tailf ファイル名■参考URL
https://uxmilk.jp/12218▼PHPのログ
これしか使ってない
log::info('abcdeとかとか・・なんでも日本語もいけました')■参照URL
http://fuelphp.jp/docs/1.7/classes/log.html▼Gitコマンド
普段SourceTreeでコマンドあんまり打たないからリンクだけ貼っておこう。
https://qiita.com/2m1tsu3/items/6d49374230afab251337
- 投稿日:2020-03-23T15:41:38+09:00
ポートフォリオ
記事の概要
PHP,MySQLを使って作った掲示板アプリです。
レスポンシブ対応してあります。作った背景
自分の母親がピアノ教室の先生をやっていて、生徒同士や先生と生徒が気軽に情報を交換したり、質問ができるようなものを作りたいと思ったからです。
機能
会員登録していなくても掲示板を見ることができ、会員登録することでメッセージを投稿できるようになるといった感じです。
会員登録
会員のお名前、メールアドレス、パスワードを入力します。
会員登録する際に、空欄があったり、既に登録されている会員だったり、パスワードが3文字以下だった場合は、エラーメッセージを表示するようにしました。
ログイン機能
メールアドレスとパスワードでログインができるといったシステムです。
ログインでも空欄があったり、登録されていない場合などはエラーメッセージを表示します。
メッセージ送信機能
自由にメッセージを投稿することができます。
また、返信することもできます。
削除機能
ログアウト機能
- 投稿日:2020-03-23T14:00:30+09:00
WordPressブログの始め方を徹底解説します!
以下の記事をご参考に!
- 投稿日:2020-03-23T12:58:59+09:00
Nginxのエラー「413 Request Entity Too Large」の対処
問題
Nginxを使ったアプリにおいて少し大きめのファイルをアップロードしたところ、このようなエラーが
ファイルサイズが大きすぎるためこのようなエラーが出るようです。
Nginxはデフォルトでは最大のアップロードのサイズが1MBとなっているようです。
対処法
Nginxの設定を変更
自分は環境構築にDockerを利用しているのでdocker/nginx/default.confを編集します。
default.confserver { listen 0.0.0.0:80; server_name localhost; charset utf-8; client_max_body_size 10M; #追加serverブロック内にclient_max_body_sizeの項目を追加またはサイズの変更をします。
php.iniの設定を変更
自分の場合はphp側の変更をしなくても行けたのですが、必要な場合もあるようなのでメモ程度に書きます。
post_max_sizeとupload_max_filesizeの項目を編集します。php.inipost_max_size = 10M upload_max_filesize = 10M設定を変更したらnginxを再起動します。
- 投稿日:2020-03-23T11:23:32+09:00
正規表現で制御文字以外とマッチさせる方法(in PHP)
※半角スペースは制御文字に含めない
preg_match('/\A[^\x00-\x1f\x7f]+\z/', $text)参考: https://kanonji.hatenadiary.com/entry/20100226/1267173195
- 投稿日:2020-03-23T10:15:32+09:00
lockファイルがコンフリクトしたときの対処法
ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪
------------------- ↓ 余談はここから ↓-------------------
lockファイルでインストールを制御ってのは、
割と理想論だと思っている。まぁ、それはいいとして、
lockファイルをコミットすると、
ほぼ間違いなくコンフリクトする。
そんなときの対処法を残しておこう。
------------------- ↓ 本題はここから ↓-------------------
composer.lock
コンフリクトを適当に解消して以下のコマンドを打つ
$ composer update --lockpackage-lock.json
コンフリクトした状態のまま以下のコマンドを打つ
$ npm install
- 投稿日:2020-03-23T09:39:27+09:00
Laravel7 新たに追加された3つのマイグレーションエイリアス
Laravel7 で追加されたマイグレーションエイリアス
使用できるカラムタイプのエイリアス
id
foreignId
外部キー制約のエイリアス
constrained
上記の3つのエイリアスが追加されてます。
環境
$ php artisan -V Laravel Framework 7.2.2使い方
Schema::table('posts', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained(); });上の定義は、下記のように定義したのと同じ内容になります。
Schema::table('posts', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('user_id'); $table->foreign('user_id')->references('id')->on('users'); });補足
- https://github.com/laravel/framework/blob/7.x/src/Illuminate/Database/Schema/Blueprint.php
- https://github.com/laravel/framework/blob/7.x/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php
id
src/Illuminate/Database/Schema/Blueprint.php/** * Create a new auto-incrementing big integer (8-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function id($column = 'id') { return $this->bigIncrements($column); }シンプルなエイリアスですね。
個人的にはbigIncrements
って指定されてた方が分かりやすいと思うんですけど...foreignId
src/Illuminate/Database/Schema/Blueprint.php/** * Create a new unsigned big integer (8-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ForeignIdColumnDefinition */ public function foreignId($column) { $this->columns[] = $column = new ForeignIdColumnDefinition($this, [ 'type' => 'bigInteger', 'name' => $column, 'autoIncrement' => false, 'unsigned' => true, ]); return $column; }
ForeignIdColumnDefinition
のインスタンスが返ってきますね。constrained
src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php/** * Create a foreign key constraint on this column referencing the "id" column of the conventionally related table. * * @param string|null $table * @return \Illuminate\Support\Fluent|\Illuminate\Database\Schema\ForeignKeyDefinition */ public function constrained($table = null) { return $this->references('id')->on($table ?: Str::plural(Str::before($this->name, '_id'))); }
foreignId
に返ってきたForeignIdColumnDefinition
にメソッドチェーンでつなげて呼び出します。
$table->foreign('user_id')->references('id')->on('users');
このようにテーブル名を指定しますが、->foreign('user_id')
からusers
と複数形のテーブルを自動的に設定してくれます。
- 投稿日:2020-03-23T09:39:27+09:00
Laravel7 新たに追加された id, foreignId, constrained マイグレーションエイリアス
Laravel7 で追加されたマイグレーションエイリアス
使用できるカラムタイプのエイリアス
id
foreignId
外部キー制約のエイリアス
constrained
上記の3つのエイリアスが追加されてます。
環境
$ php artisan -V Laravel Framework 7.2.2使い方
Schema::table('posts', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained(); });上の定義は、下記のように定義したのと同じ内容になります。
Schema::table('posts', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('user_id'); $table->foreign('user_id')->references('id')->on('users'); });補足
- https://github.com/laravel/framework/blob/7.x/src/Illuminate/Database/Schema/Blueprint.php
- https://github.com/laravel/framework/blob/7.x/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php
id
src/Illuminate/Database/Schema/Blueprint.php/** * Create a new auto-incrementing big integer (8-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function id($column = 'id') { return $this->bigIncrements($column); }シンプルなエイリアスですね。
個人的にはbigIncrements
って指定されてた方が分かりやすいと思うんですけど...foreignId
src/Illuminate/Database/Schema/Blueprint.php/** * Create a new unsigned big integer (8-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ForeignIdColumnDefinition */ public function foreignId($column) { $this->columns[] = $column = new ForeignIdColumnDefinition($this, [ 'type' => 'bigInteger', 'name' => $column, 'autoIncrement' => false, 'unsigned' => true, ]); return $column; }
ForeignIdColumnDefinition
のインスタンスが返ってきますね。constrained
src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php/** * Create a foreign key constraint on this column referencing the "id" column of the conventionally related table. * * @param string|null $table * @return \Illuminate\Support\Fluent|\Illuminate\Database\Schema\ForeignKeyDefinition */ public function constrained($table = null) { return $this->references('id')->on($table ?: Str::plural(Str::before($this->name, '_id'))); }
foreignId
に返ってきたForeignIdColumnDefinition
にメソッドチェーンでつなげて呼び出します。
$table->foreign('user_id')->references('id')->on('users');
このようにテーブル名を指定しますが、->foreign('user_id')
からusers
と複数形のテーブルを自動的に設定してくれます。
- 投稿日:2020-03-23T09:27:16+09:00
PHPStormでクラスのnamespaceを移動する
以前 PHPStormでnamespaceを一括変更 でディレクトリの移動にあわせてnamespaceも一緒に移動する方法を書いたのですが、今回はクラスを特定のnamespaceに移動させる方法です。
PHPStormでファイルを開き、クラス名にカーソルを当てた状態でF6キーを押すと、
namespaceの移動のダイアログが出ます。Move Class 〇〇 to namespaceのところを編集して保存するとクラスのnamespaceとあわせてファイルのディレクトリも移動します。
- 投稿日:2020-03-23T08:25:03+09:00
PHP Intelephense の有償版を Neovim で使ってみる
PHP Intelephense は PHP の Language Server の一つ。
VS Code での利用例は
- VSCode PHP用のインテリセンス拡張機能は「Intelephense」の方がオススメ! │ wonwon eater
- VS CodeのPHP Intelliphenseがとても心地よくコードを補完してくれる件 - Qiita
- VSCode で PHP 開発するならインテリセンス最強の intelephense を使おう | 株式会社ビヨンド
など様々見られる一方、 Neovim での利用に関する情報があまり見つからなかったので、導入手順をメモ。
また有償版だとクラスやメソッドの実装へのジャンプやリネームなどの機能も利用できるようになるとのことで、せっかくなので有償版を購入して使ってみた。有償版のライセンスキー取得
ライセンス購入ページ から必要な情報を入力して購入する(記事投稿時点で ¥1,000 )。
後から送付されるメールにライセンスキーが記載されている。Neovim 側の設定
language server のプラグインは coc.nvim を使用した。
coc.nvim の PHP 拡張である coc-phpls を使えばライセンスキーをcoc-settings.json
に記載するだけで特にその他の設定なしで利用できる。
ちなみにキーに含まれるlicence
のスペルはlicense
ではないので注意( Intelephense の開発元はオーストラリアらしいが、アメリカ英語と異なる?)。coc-settings.json{ "intelephense.licenceKey": "your licence key", }後は
:CocInstall phpls
で拡張機能を追加すればオーケー。課題
前述した実装へのジャンプやリネームもきちんと動作したので、 PHP の language server としてはこれがベストかもしれない。
ただインターフェースへのジャンプが上手くできなかったりするので、まだ諸々の設定を調べる余地がありそう...。
- 投稿日:2020-03-23T08:03:48+09:00
Mac Catalina 10.15 に、古いバージョンのPHPをインストールする
Mac Catalina 10.15 に、古いバージョンのPHPをインストールする
CakePHP2のアプリを修正依頼が合ったが、Mac Catalinaではhomebrewに
もう古いバージョンが無く・・・(なんでそんなに古いまま、ほっといたんだよってツッコミはなしで、、、)
brew tap exolnet/homebrew-deprecated
でも、php 5.6どうしても、php5.5を入れたいと調べてたら、binary packageを入れる方法がありました。
PHP 5.3〜PHP 7.3がある
インストールする
curl -s https://php-osx.liip.ch/install.sh | bash -s 5.5pathを通す
export PATH=/usr/local/php5/bin:$PATH
- 投稿日:2020-03-23T04:49:28+09:00
Phoenix LiveViewでもPHP的に気軽なWebアプリ開発ができるんです
fukuoka.ex/kokura.exのpiacereです
ご覧いただいて、ありがとうございます前作のPHP的気軽さでWebアプリを作る方法を、今度はLiveViewでも展開してみたいと思います
前作同様、LiveViewにおいても、ルーティングは不要になります
なおLiveViewでは、パラメータ渡しによるMPA(Multiple Page Application)的ハンドリングでは無く、handle_event()等によるSPA(Single Page Application)的イベントハンドラが中心となるのですが、ここでは、できるだけMPAのようなテイストになるように作ってみます
LiveViewでのSPAフォーム開発に抵抗が高い方もまだまだ多いんでは無いかと思いますが、このスタートだと案外、気楽になれるかもです
本コラムの検証環境
本コラムは、以下環境で検証しています(Windowsで実施していますが、Linuxやmacでも動作する想定です)
- Windows 10
- Elixir 1.10.1 ※最新版のインストール手順はコチラ
- Phoenix 1.4.15 ※最新版のインストール手順はコチラ
- Node.js 12.14.0
なおPhoenixは、1.3系でも動作します(ElixirもPhoenixのバージョンに準じた古いものでも大丈夫です)
事前準備:Phoenix PJの作成、LiveView導入
まずPhoenix PJを作成します
mix phx.new basic --no-ecto … Fetch and install dependencies? [Yn] 【Nを入力してEnter】 cd basic続けて、下記コラムの手順に従って、Phoenix PJにLiveViewを導入します(ただしPJ名は、LvSampleでは無く、上記で作成したBasicで読み替えて実施してください)
LiveViewでSPA開発①: Elixirのみでフロントのリアルタイム入力/反映するSPAを実現
https://qiita.com/piacerex/items/3f8ee18c9443d63955bf更に、LiveView用HTMLをテンプレートファイル化するために、下記コラムも実施します(こちらもPJ名は、LvSampleでは無く、上記で作成したBasicで読み替えて実施してください)
LiveViewでSPAを作る③: LiveView用のHTMLをテンプレートファイルに分離
https://qiita.com/piacerex/items/5b1aabb0c45bb9934bb9ここまでが終わったら、ブラウザで「
http://localhost:4000/realtime
」にアクセスすると、LiveViewで作成された、Qiitaリアルタイム検索SPAが表示されることを確認して、準備完了です
手順①:html.leexの表示をルーティング不要に
まずはルーティングで、前作同様、「*_ path」というワイルドカード指定をすることで、多階層のURLパスを「_path」パラメータから取得できるようにします
接続先のコントローラは、LiveView専用のマッピングコントローラとします
なお、前作の続きでやられている場合は、getやpostのワイルドカード指定とぶつかるため、getやpostの分は、コメントアウトや削除しておいてください
lib/basic_web/router.exdefmodule BasicWeb.Router do … scope "/", BasicWeb do pipe_through :browser # get "/", PageController, :index # <-- remove here # post "/*_path", PageController, :index # <-- remove here # get "/*_path", PageController, :index # <-- remove here live "/*_path", LiveViewController # <-- add here …手順②:html.leexの複数階層フォルダ指定可能に
render()の第2引数に指定するパスの複数階層指定は、前作と全く同じView設定記述になります(前作の続きでやっている場合は、この手順自体が実施不要です)
lib/basic_web.exdefmodule BasicWeb do … def view do quote do use Phoenix.View, pattern: "**/*", # <-- add here root: "lib/basic_web/templates", namespace: BasicWeb, …手順③:パスの自動マッピング、GETパラメータの素通し
LiveView専用のマッピングコントローラを追加します
「_path」パラメータのフォルダ階層リストを、html.leexのパスにマッピングします
通常だと、mount()の第1引数であるparamsは、「_params」と利用不可にしますが、ここではGETパラメータを素通ししたいので、アンダースコア無しの「params」で定義し、テンプレートに引き渡します
lib/basic_web/live/liveview_controller.exdefmodule BasicWeb.LiveViewController do use Phoenix.LiveView def render( assigns ) do params = assigns.params template = if params[ "_path" ] == nil, do: "blank.html", else: to_path_string( params[ "_path" ] ) <> ".html" BasicWeb.LiveView.render( template, assigns ) end def to_path_string( path_list ), do: String.slice( Enum.reduce( path_list, "", & "#{ &2 }#{ &1 }/" ), 0..-2 ) def mount( params, _session, socket ) do { :ok, assign( socket, params: params ) } end endLiveView起動直後は、assignsに「_path」パラメータが未指定(というかparams自体が未指定)なので、空のページを追加しておきます
lib/basic_web/templates/live/blank.html.leex<h1>Now loading...</h1>手順④:html.leexページを追加する
1)templates/live直下にhtml.leex追加
これで、page配下にhtml.leexを追加するだけで、新たなLiveViewページが追加可能となったので、追加してみます
lib/basic_web/templates/live/another.html.leex<h1>This is another page</h1> <%= inspect( System.build_info() ) %> <hr> <%= inspect( @params ) %>ブラウザで
「http://localhost:4000/another」
にアクセスすると、以下のようなページが表示されます
URLにパラメータを指定してアクセスすると、@ paramsパラメータに入るので、GET処理も気軽に使えるようになります
2)templates/live配下のサブフォルダ下にhtml.leex追加
liveフォルダ配下にフォルダ階層を掘って、そこにhtml.leexを配置しても動きます
「uvw」というフォルダを掘り、「xyz.html.leex」というLiveViewテンプレートを追加します
lib/basic_web/templates/page/uvw/xyz.html.leex<h1>I'm xyz page</h1> <%= inspect( @params ) %>ブラウザで
「http://localhost:4000/uvw/xyz」
にアクセスすると、以下のようなページが表示されます(「_path」パラメータにフォルダ階層がリストで入っていることも確認できます)
3)MPAフォームのノリでSPAフォームを気軽に書く
ここまでの手順により、LiveViewページは、html.leex追加で増やせるようになりましたが、前作で扱ったようなサーバサイドレンダリング(SSR)でのMPAと異なり、LiveViewはSPAなので、GETやPOSTによるページ間のパラメータ渡しは行いません
代わりに、LiveViewコントローラにハンドラを追加したり、mount()にパラメータ追加することで処理するため、MPAとは書き方が根本的に異なります
しかし、パラメータ設計によっては、MPAソックリな記述も可能なため、これを実現してみます
まず、引き渡すパラメータは、paramsのみとすることで、mount()のパラメータリストをいじる必要が無くなります
次に、submitのハンドラは、formタグに「phx-submit」を指定し、コントローラ側にハンドラを設けることで実現します
なお、「_path」パラメータは、「phx-submit」や「phx-change」のたびにrouter.exから来る訳では無いため、パス形式に直しておき、hiddenパラメータ化して持ち回るようにします
lib/basic_web/templates/page/uvw/form.html.leex<h1>I'm form page</h1> <font color="blue"><h2><%= @params[ "submited" ] %></h2></font> <form phx-submit="submit"> <p> メモ: <input name="memo" type="text"> </p> <p> 好きな言語: <input name="language[]" type="checkbox" value="Elixir">Elixir <input name="language[]" type="checkbox" value="Rust">Rust <input name="language[]" type="checkbox" value="Julia">Julia </p> <p> 年代: <select name="age"> <option value="10">10代 <option value="20">20代 <option value="30">30代 <option value="30">40代 <option value="50">50代 <option value="60">60代 <option value="70">70代以上 </select> </p> <input type="submit" value="送信"> <input name="_path" type="hidden" value="<%= @_path %>"> </form> <%= inspect @params %>LiveView用コントローラの内容は、下記で置き換えます
まずrender()では、「_path」パラメータをリスト形式とパス形式の両方を受け付けられるように変更します)
mount()は、変更無しです
handle_event()が、「phx-submit」のためのハンドラで、ここではフォームサブミット時に、メッセージが変わるようにしているだけですが、実際はDB登録などのサブミット時処理を入れます
lib/basic_web/live/liveview_controller.exdefmodule BasicWeb.LiveViewController do use Phoenix.LiveView def render( assigns ) do params = assigns.params page = if params[ "_path" ] == nil do "blank.html" else if is_list( params[ "_path" ] ) do to_path_string( params[ "_path" ] ) <> ".html" else params[ "_path" ] <> ".html" end end BasicWeb.LiveView.render( page, assigns ) end def mount( params, _session, socket ) do { :ok, assign( socket, params: params, _path: to_path_string( params[ "_path" ] ) ) } end def to_path_string( path_list ), do: String.slice( Enum.reduce( path_list, "", & "#{ &2 }#{ &1 }/" ), 0..-2 ) def handle_event( "submit", params, socket ) do new_params = params |> Map.put( "submited", "submited" ) { :noreply, assign( socket, params: new_params ) } end endブラウザで
「http://localhost:4000/uvw/xyz」
にアクセスすると、以下のようなページが表示されます(「_path」パラメータにフォルダ階層がリストで入っていることも確認できます)
「送信」ボタンを押下すると、サブミット処理に相当する処理が走り、画面表示が変わります
なお、「_path」をhiddenパラメータ化しないと、入力や「送信」ボタン押下した瞬間に、以下のブランクページが表示されます
4)バリデーションチェックをリアルタイムで実行
よりSPAらしい造りにするため、フォーム内容が変更された際は、バリデーションチェックがリアルタイムで実行されるようにしてみましょう
formタグに「phx-change」を指定し、コントローラ側に変更時ハンドラを設けます
ちなみに入力都度、「phx-change」が呼び出されることで、入力内容が消えてしまうため、維持するためのコードも入れています(分かりやすくするために愚直な書き方をしています、実際はフォーム値のリストを渡してループ展開するような書き方が良いでしょう)
下記内容で、form.html.leexを置き換えてください
lib/basic_web/templates/page/uvw/form.html.leex<h1>I'm form page</h1> <font color="red"><%= @params[ "validated" ] %></font><font color="blue"><h2><%= @params[ "submited" ] %></h2></font> <form phx-submit="submit" phx-change="change"> <p> メモ: <input name="memo" type="text" value="<%= @params[ "memo" ] %>"> </p> <p> 好きな言語: <input name="language[]" type="checkbox" value="Elixir" <%= if @params[ "language" ] != nil && Enum.any?( @params[ "language" ], & &1 == "Elixir" ), do: "checked", else: "" %>>Elixir <input name="language[]" type="checkbox" value="Rust" <%= if @params[ "language" ] != nil && Enum.any?( @params[ "language" ], & &1 == "Rust" ), do: "checked", else: "" %>>Rust <input name="language[]" type="checkbox" value="Julia" <%= if @params[ "language" ] != nil && Enum.any?( @params[ "language" ], & &1 == "Julia" ), do: "checked", else: "" %>>Julia </p> <p> 年代: <select name="age"> <option value="10" <%= if @params[ "age" ] == "10", do: "selected", else: "" %>>10代 <option value="20" <%= if @params[ "age" ] == "20", do: "selected", else: "" %>>20代 <option value="30" <%= if @params[ "age" ] == "30", do: "selected", else: "" %>>30代 <option value="30" <%= if @params[ "age" ] == "40", do: "selected", else: "" %>>40代 <option value="50" <%= if @params[ "age" ] == "50", do: "selected", else: "" %>>50代 <option value="60" <%= if @params[ "age" ] == "60", do: "selected", else: "" %>>60代 <option value="70" <%= if @params[ "age" ] == "70", do: "selected", else: "" %>>70代以上 </select> </p> <input type="submit" value="送信"> <input name="_path" type="hidden" value="<%= @_path %>"> </form> <%= inspect @params %>バリデーションチェック用のhandle_event()も追加します
ここでも、バリデーションチェックエラー時のメッセージを愚直に作っていますが、もっとスマートな書き方をすることもできますし、Ectoのchangesetを使うこともできます
lib/basic_web/live/liveview_controller.exdefmodule BasicWeb.LiveViewController do … def handle_event( "change", params, socket ) do validated = ( if String.length( params[ "memo" ] ) > 30, do: "(メモは30文字以内にしてください)", else: "" ) <> ( if params[ "language" ] == [], do: "(言語は必ず1つ選択してください)", else: "" ) new_params = params |> Map.put( "validated", validated ) |> Map.put( "submited", "" ) { :noreply, assign( socket, params: new_params ) } end …ブラウザで
「http://localhost:4000/uvw/xyz」
にアクセスし、入力を行うと、バリデーションチェックに相当する処理が走り、画面表示が変わります(「_path」パラメータがパス形式の文字列に変更されていることが確認できます)
5)フォーム毎にバリデーション/サブミットを書き分けるには?
複数のフォームがある場合、html.leexの方は簡単に追加できる一方、フォーム毎に入力項目は異なるため、バリデーション/サブミットを書き分ける必要がありますが、コントローラは1つのため、何らかの対応が必要です
最も簡単なのは、「_path」パラメータにパスがあるため、下記のように、各パス毎にスイッチしてあげることです
lib/basic_web/live/liveview_controller.exdefmodule BasicWeb.LiveViewController do … def handle_event( "change", params, socket ) do validated= case params[ "_path" ] do "uvw/form" => ( if String.length( params[ "memo" ] ) > 30, do: "(メモは30文字以内にしてください)", else: "" ) <> ( if params[ "language" ] == [], do: "(言語は必ず1つ選択してください)", else: "" ) _ => "(undefined validatd)" end new_params = params |> Map.put( "validated", validated) |> Map.put( "submited", "" ) { :noreply, assign( socket, params: new_params ) } endもちろん、もっとスマートに書ける訳ですが、入門的な内容としては、ここまでで充分かと思います
終わり
LiveViewでも、PHPみたいに気軽なWebアプリ開発ができるようになりました
このテクニックを使って、LiveView SPAによるWebアプリ構築にも慣れていっていただけたら幸いです
Vue.jsやReact等でリアルタイムフロントに慣れている方であれば、ハンドラを多少覚えるだけで使いこなせるハズです
p.s.このコラムが、面白かったり、役に立ったら…
- 投稿日:2020-03-23T03:22:53+09:00
【Laravel7.2】Migrationを用いてテーブルを作成。Seederを用いてデータを投入する
前提環境
Laravel7.2環境を構築。Welcome!画面が表示された状態から開始。
その他、DBの設定等も済み。詳細は以下参照。【準備編】https://qiita.com/katsuhito_01/items/db5b9581a2b6af6dc803
【導入編】https://qiita.com/katsuhito_01/items/439e3af4cea8ff00832cMigrationを用いてテーブルを作成
まずはMigrationを用いて参照するテーブルを作成する。今回は都道府県マスタを作成。
Migration作成
Laravelプロジェクトのディレクトリ内にて、以下コマンドを実行
# php artisan make:migration create_mst_prefectures_table Created Migration: 2020_03_22_163920_create_mst_prefectures_tableすると、database\migrations\日付_create_mst_prefectures_table.phpというファイルが作成される。
作成されたファイルをいじり、作成するテーブルの構造を記述する。
今回は以下のように記述。【参考】:https://readouble.com/laravel/7.x/ja/migrations.html
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateMstPrefecturesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('mst_prefectures', function (Blueprint $table) { $table->integer('id')->primary(); $table->string('name', 10); $table->string('name_kana', 10); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('mst_prefectures'); } }Migration実行
構造を記述したら、Migrationを実行。
# php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.02 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.01 seconds) Migrating: 2020_03_22_163920_create_mst_prefectures_table Migrated: 2020_03_22_163920_create_mst_prefectures_table (0.01 seconds)MySQLに入り、テーブルを確認。
mysql> show tables; +-----------------------+ | Tables_in_mypage01_db | +-----------------------+ | failed_jobs | | migrations | | mst_prefectures | | users | +-----------------------+ 4 rows in set (0.00 sec) mysql> desc mst_prefectures; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(10) | NO | | NULL | | | name_kana | varchar(10) | NO | | NULL | | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | +------------+-------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)出来てますね!
Seederを用いてテーブルにデータを投入
市区町村マスタができたので、Seederを用いてデータを投入する。
Modelを作成する
まずはModelを作成。
以下実行で、app直下にModelが作成される。
とりあえず今は何も書かない。php artisan make:model MstPrefectureちなみに作成されたModelの中身を見てみると、空のクラスがあるだけ。
テーブルとの紐づけを明示する記述がどこにもない。明示的に設定することもできるが、公式ドキュメントには以下の記述がある。
他の名前を明示的に指定しない限り、クラス名を複数形の「スネークケース」にしたものが、テーブル名として使用されます。今回の例で、EloquentはFlightモデルをflightsテーブルに保存します。モデルのtableプロパティを定義し、カスタムテーブル名を指定することもできます。
【引用元】https://readouble.com/laravel/5.7/ja/eloquent.html
今回でいうと、「MstPrefectur」を「mst_prefectures」と自動的に結び付けてつけてくれる。
逆を言うと、テーブル名を決める際はLaravelの命名規則に則っていないと、こういった恩恵が受けられない。
「おせっかいだ」と思った方は、Modelのクラス内に以下記述を追加することで、Modelとテーブルを明示的に紐づけることができる。protected $table = 'テーブル名';Seeder作成
続いてSeederを作成。
# php artisan make:seeder MstPrefecturesSeeder Seeder created successfully.以下のファイルが作成される。
database\seeds\MstPrefecturesSeeder.php早速中身をいじり、投入するデータを記述する。
<?php use Illuminate\Database\Seeder; use App\MstPrefecture; class MstPrefecturesSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { MstPrefecture::insert([ ['id' => 1, 'name' => '北海道', 'name_kana' => 'ホッカイドウ', 'created_at' => now(), 'updated_at' => now()], ['id' => 2, 'name' => '青森県', 'name_kana' => 'アオモリケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 3, 'name' => '岩手県', 'name_kana' => 'イワテケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 4, 'name' => '宮城県', 'name_kana' => 'ミヤギケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 5, 'name' => '秋田県', 'name_kana' => 'アキタケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 6, 'name' => '山形県', 'name_kana' => 'ヤマガタケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 7, 'name' => '福島県', 'name_kana' => 'フクシマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 8, 'name' => '茨城県', 'name_kana' => 'イバラキケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 9, 'name' => '栃木県', 'name_kana' => 'トチギケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 10, 'name' => '群馬県', 'name_kana' => 'グンマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 11, 'name' => '埼玉県', 'name_kana' => 'サイタマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 12, 'name' => '千葉県', 'name_kana' => 'チバケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 13, 'name' => '東京都', 'name_kana' => 'トウキョウト', 'created_at' => now(), 'updated_at' => now()], ['id' => 14, 'name' => '神奈川県', 'name_kana' => 'カナガワケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 15, 'name' => '新潟県', 'name_kana' => 'ニイガタケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 16, 'name' => '富山県', 'name_kana' => 'トヤマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 17, 'name' => '石川県', 'name_kana' => 'イシカワケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 18, 'name' => '福井県', 'name_kana' => 'フクイケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 19, 'name' => '山梨県', 'name_kana' => 'ヤマナシケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 20, 'name' => '長野県', 'name_kana' => 'ナガノケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 21, 'name' => '岐阜県', 'name_kana' => 'ギフケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 22, 'name' => '静岡県', 'name_kana' => 'シズオカケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 23, 'name' => '愛知県', 'name_kana' => 'アイチケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 24, 'name' => '三重県', 'name_kana' => 'ミエケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 25, 'name' => '滋賀県', 'name_kana' => 'シガケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 26, 'name' => '京都府', 'name_kana' => 'キョウトフ', 'created_at' => now(), 'updated_at' => now()], ['id' => 27, 'name' => '大阪府', 'name_kana' => 'オオサカフ', 'created_at' => now(), 'updated_at' => now()], ['id' => 28, 'name' => '兵庫県', 'name_kana' => 'ヒョウゴケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 29, 'name' => '奈良県', 'name_kana' => 'ナラケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 30, 'name' => '和歌山県', 'name_kana' => 'ワカヤマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 31, 'name' => '鳥取県', 'name_kana' => 'トットリケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 32, 'name' => '島根県', 'name_kana' => 'シマネケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 33, 'name' => '岡山県', 'name_kana' => 'オカヤマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 34, 'name' => '広島県', 'name_kana' => 'ヒロシマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 35, 'name' => '山口県', 'name_kana' => 'ヤマグチケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 36, 'name' => '徳島県', 'name_kana' => 'トクシマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 37, 'name' => '香川県', 'name_kana' => 'カガワケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 38, 'name' => '愛媛県', 'name_kana' => 'エヒメケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 39, 'name' => '高知県', 'name_kana' => 'コウチケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 40, 'name' => '福岡県', 'name_kana' => 'フクオカケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 41, 'name' => '佐賀県', 'name_kana' => 'サガケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 42, 'name' => '長崎県', 'name_kana' => 'ナガサキケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 43, 'name' => '熊本県', 'name_kana' => 'クマモトケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 44, 'name' => '大分県', 'name_kana' => 'オオイタケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 45, 'name' => '宮崎県', 'name_kana' => 'ミヤザキケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 46, 'name' => '鹿児島県', 'name_kana' => 'カゴシマケン', 'created_at' => now(), 'updated_at' => now()], ['id' => 47, 'name' => '沖縄県', 'name_kana' => 'オキナワケン', 'created_at' => now(), 'updated_at' => now()] ]); } }実行するSeederに追加
投入するデータの記述ができたら、以下を編集。
実行するSeederとして追加しておく。
database\seeds\DatabaseSeeder.php<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(MstPrefecturesSeeder::class); } }Seederを実行
まずはComposerオートローダを再作成。
基本的に新しいクラスを追加したときは、このコマンドを実行しておく# composer dump-autoload Package manifest generated successfully. Generated optimized autoload files containing 4098 classesそしてSeederを実行。
# php artisan db:seed Seeding: MstPrefecturesSeeder Seeded: MstPrefecturesSeeder (0.06 seconds) Database seeding completed successfully.MySQLよりテーブルを見てみると…
mysql> select * from mst_prefectures order by id; +----+--------------+--------------------+---------------------+---------------------+ | id | name | name_kana | created_at | updated_at | +----+--------------+--------------------+---------------------+---------------------+ | 1 | 北海道 | ホッカイドウ | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 2 | 青森県 | アオモリケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 3 | 岩手県 | イワテケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 4 | 宮城県 | ミヤギケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 5 | 秋田県 | アキタケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 6 | 山形県 | ヤマガタケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 7 | 福島県 | フクシマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 8 | 茨城県 | イバラキケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 9 | 栃木県 | トチギケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 10 | 群馬県 | グンマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 11 | 埼玉県 | サイタマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 12 | 千葉県 | チバケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 13 | 東京都 | トウキョウト | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 14 | 神奈川県 | カナガワケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 15 | 新潟県 | ニイガタケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 16 | 富山県 | トヤマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 17 | 石川県 | イシカワケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 18 | 福井県 | フクイケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 19 | 山梨県 | ヤマナシケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 20 | 長野県 | ナガノケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 21 | 岐阜県 | ギフケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 22 | 静岡県 | シズオカケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 23 | 愛知県 | アイチケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 24 | 三重県 | ミエケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 25 | 滋賀県 | シガケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 26 | 京都府 | キョウトフ | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 27 | 大阪府 | オオサカフ | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 28 | 兵庫県 | ヒョウゴケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 29 | 奈良県 | ナラケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 30 | 和歌山県 | ワカヤマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 31 | 鳥取県 | トットリケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 32 | 島根県 | シマネケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 33 | 岡山県 | オカヤマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 34 | 広島県 | ヒロシマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 35 | 山口県 | ヤマグチケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 36 | 徳島県 | トクシマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 37 | 香川県 | カガワケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 38 | 愛媛県 | エヒメケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 39 | 高知県 | コウチケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 40 | 福岡県 | フクオカケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 41 | 佐賀県 | サガケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 42 | 長崎県 | ナガサキケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 43 | 熊本県 | クマモトケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 44 | 大分県 | オオイタケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 45 | 宮崎県 | ミヤザキケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 46 | 鹿児島県 | カゴシマケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | | 47 | 沖縄県 | オキナワケン | 2020-03-23 03:17:52 | 2020-03-23 03:17:52 | +----+--------------+--------------------+---------------------+---------------------+ 47 rows in set (0.00 sec)入ってますね!
今回はDatabaseSeeder記述のSeederをすべて実行する形でしたが、以下のように個別に実行することも可能。php artisan db:seed --class=MstPrefecturesSeeder次回から、CRUDを作っていきましょうか。
- 投稿日:2020-03-23T01:33:47+09:00
PHP サイト でも Capistrano (Ruby Gem)
環境
- Ruby 2.6.5
設定手順
Capistrano 設定ファイルの用意
bundle add capistrano bundle exec cap installこれで必要なファイルが作成されます。
あとは
deploy.rb
,config/deploy/*
を変更して設定完了です。ファイルを置けば使えるPHPサイトなら、認証設定程度を記述すればOKです。
設定ファイル例
staging.rb/production.rb# server configuration role :web, %w{ec2-user@123.123.123.123} # file location set :deploy_to, "/var/www/xxx"deploy.rb# application name set :application, "xxxxxx" # repository set :repo_url, "sample@sample.git.jp:/sample.git" # Default branch is :master ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp # revision to be kept set :keep_releases, 2デプロイ手順
# config/deploy/staging.rb を使ったデプロイ bundle exec cap staging deploy # config/deploy/production.rb を使ったデプロイ bundle exec cap production deployロールバック手順
cap deploy:rollbackこのほかにも
cap deploy:rollback:code
などがある。
- 投稿日:2020-03-23T00:29:40+09:00
Mac Visual Studio Code Xdebugを頑張って設定したのに全くデバッグできなくて困った話
目的
- たくさんの人に協力してもらったのに思いも寄らない障壁があったため記憶に留めるためにまとめる
実施環境
項目 情報 OS macOS Catalina(10.15.3) ハードウェア MacBook Pro (16-inch ,2019) プロセッサ 2.6 GHz 6コアIntel Core i7 メモリ 16 GB 2667 MHz DDR4 グラフィックス AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB 困った内容
- 下記の手順を参考にMacとVisual Studio CodeとXdebugを使ったローカルデバッグ環境を立ち上げた。
下記の問題が発生した。
原因
- セキュリティソフトのファイアウォールが本機能をブロックしてしまっていた。
一時的にファイアウォールの設定を切りサイドデバッグモードを起動したところ各ボタンもアクティブになり単一行での実行も可能になった。
謝辞
- 本件に関して数多くの方からフォローしていただきました。
- 筆者の問題解決に協力いただいた皆様に感謝申し上げるとともに、これから質問する際は各種詳細情報を明確にした上で、自分がどこまでわかっていて何ができていないのかを伝えて質問するように努めます。
- この度は誠にありがとうございます。