- 投稿日:2020-09-25T22:30:30+09:00
[Laravel] 特定のマイグレーションだけをマイグレート、ロールバックしたい!!!
初めに
入社してから与えられた課題で、特定のマイグレーション以外をロールバックして、修正、特定のマイグレーション以外を再び実行するという操作をしたくなったのですが、なかなか情報が見つからず、たくさんのサイトを見て得た情報と最終的に見つけた自己流の解決策を紹介します。
マイグレーションは連続的なものであるという前提
いざというときにLaravelがデータを安全にロールバックできるようにするための仕組みがマイグレーションというものらしいです。
だから、マイグレーションはそれらが作成された順にひとつずつ実行しています。この前提から特定のマイグレーションだけを実行することは邪道なのではという疑念を抱きつつ、解決策へ、、、
解決策
特定のマイグレーションだけをマイグレートする
php artisan migrate:refresh
を応用して使います。マイグレーションを指定したファイルから1つだけマイグレートする
php artisan migrate:refresh --step=1 --path=/database/migrations/ファイル名step=○の数字を変えることで、マイグレートするファイルの数を変更できます。
特定のマイグレーションだけをロールバックする
コメントアウトを使います。
public function up() { Schema::create('flights', function (Blueprint $table) { #$table->increments('id'); #$table->string('name'); #$table->string('airline'); #$table->timestamps(); }); } public function down() { #Schema::drop('flights'); }ロールバックしたくないファイルを上記のようにコメントアウトし、ロールバックすると、このファイルが無視されます。
- 投稿日:2020-09-25T21:03:13+09:00
PHPUnitで始めるユニットテスト
目次
ユニットテストとは
インストール方法
簡単なテストコードの書き方と実行方法
テスト結果の確認方法
複数データのテスト
プライベートメソッドのテストユニットテストとは
プログラムの小さな機能単位に対して行う動作確認のこと
ある操作を行った時に結果がどうなるかを
順々に試していく作業を自動化するためにあるインストール方法
composer
はインストールされている前提で進めていきます。
インストールしてない方はインストールしてから戻ってきてください
これは推奨されていないやり方ですが、composer global require 'phpunit/phpunit:*' echo "export PATH=\$PATH:\$HOME/.config/composer/vendor/bin" >> ~/.bash_profile source ~/.bash_profile
phpunit -version
で確認してみてください
推奨されているやり方は以下の通りですwget https://phar.phpunit.de/phpunit-|version|.phar chmod +x phpunit-|version|.phar ./phpunit-|version|.phar --version参考
https://phpunit.readthedocs.io/ja/latest/installation.html簡単なテストコードの書き方と実行方法
User.php<?php class User { public $name; public __construct($name) { $this->name = $name; } public function sayHi(): string { //return 'Hi ' . $this->name; return 'Hi ' . $name; } }UserTest.php<?php require __DIR__ . '/User.php'; class User extends PHPUnit\Framework\TestCasee { public function testConstruct() { $user = new User('Perry'); $this->assertEquals('Perry', $user->name); } public function testSayHi() { $user = new User('Satoru'); $test = $user->sayHi(); $expected = 'Hi Satoru'; $this->assertEquals($expected, $test); } }これを実行するときは
phpunit UserTest.php
とすれば良い
ディレクトリ単位でも実行することができる実際にこれを実行すると
PHPUnit 7.5.20 by Sebastian Bergmann and contributors. .E 2 / 2 (100%) Time: 24 ms, Memory: 4.00 MB There was 1 error: 1) UserTest::testCreateMessage Undefined variable: name /PATH/User.php:11 /PATH/UserTest.php:13 ERRORS! Tests: 2, Assertions: 1, Errors: 1.こんな感じで帰ってくる
最初の.
はテスト通ったよってこと
その次のE
はエラーを表している
エラーが出た場合は上のように内容が詳細に記される
最初の行ではテストメソッドの名前とエラーの個数が表示される
次の行ではエラーの内容
次に該当箇所が表示され、その次の行で、UserTest.php
の13行目を実行した時に
エラーが発生したと丁寧に書いてくれていますそれではコードを修正しましょう
User.php<?php class User { public $name; public __construct($name) { $this->name = $name; } public function sayHi(): string { return 'Hi ' . $this->name; } }これで実行してみましょう
.. 2 / 2 (100%) Time: 22 ms, Memory: 4.00 MB OK (2 tests, 2 assertions)いい感じですね!
ちなみに文字リテラルが間違っていた場合はE
ではなく
F
が出力されます
スキップされた際はS
らしいですみたことないけど!このように
テスト実行->失敗した場合は修正->テスト
を繰り返して進めていきます
今回はassertEqual
しか使わなかったですが、他にもたくさんあるので調べてみてください
分かりやすい記事があったので説明は省略します
https://qiita.com/rev84/items/12fbd16d210d6a86eff9
https://www.wakuwakubank.com/posts/425-php-php-unit/複数データのテスト
データプロバイダを使って複数のデータをまとめてテストしましょう
Calc.php<?php class Calc { private $number1; private $number2; public function __construct(int $number1, int $number2) { $this->number1 = $number1; $this->number2 = $number2; } public function calc(string $option = '+'): int { switch ($option) { case '+': $answer = $this->number1 + $this->number2; break; case '-': $answer = $this->number1 - $this->number2; break; case '*': $answer = $this->number1 * $this->number2; break; case '/': if ($this->number2 == 0) return false; $answer = $this->number1 / $this->number2; break; default: return false; } return $answer; } }CalcTest.php<?php require_once __DIR__ . '/Calc.php'; class CalcTest extends PHPUnit\Framework\TestCase { /** * @dataProvider numberProvider */ public function testCalc(int $number1, int $number2, string $option, int $expected) { $calc = new Calc($number1, $number2); $test = $calc->calc($option); $this->assertEquals($expected, $test); } public function numberProvider() { return [ [1, 2, '+', 3], [1, 2, '-', 3], [1, 2, '*', 3], [1, 2, '/', 3], [3, 4, '+', 12], [3, 4, '-', 12], [3, 4, '*', 12], [3, 4, '/', 12], [7, 8, '+', 15], [7, 8, '-', 15], [7, 8, '*', 15], [7, 8, '/', 15], ]; } }実行方法は先ほどのコマンドに
--debug
オプションをつけるだけー実行結果は以下のようになりました
.FFFFF.F.FFF 12 / 12 (100%) Time: 24 ms, Memory: 4.00 MB There were 9 failures: 1) CalcTest::testCalc with data set #1 (1, 2, '-', 3) Failed asserting that -1 matches expected 3. /PATH/CalcTest.php:12 2) CalcTest::testCalc with data set #2 (1, 2, '*', 3) Failed asserting that 2 matches expected 3. /PATH/CalcTest.php:12 3) CalcTest::testCalc with data set #3 (1, 2, '/', 3) Failed asserting that 0 matches expected 3. /PATH/CalcTest.php:12 4) CalcTest::testCalc with data set #4 (3, 4, '+', 12) Failed asserting that 7 matches expected 12. /PATH/CalcTest.php:12 5) CalcTest::testCalc with data set #5 (3, 4, '-', 12) Failed asserting that -1 matches expected 12. /PATH/CalcTest.php:12 6) CalcTest::testCalc with data set #7 (3, 4, '/', 12) Failed asserting that 0 matches expected 12. /PATH/CalcTest.php:12 7) CalcTest::testCalc with data set #9 (7, 8, '-', 15) Failed asserting that -1 matches expected 15. /PATH/CalcTest.php:12 8) CalcTest::testCalc with data set #10 (7, 8, '*', 15) Failed asserting that 56 matches expected 15. /PATH/CalcTest.php:12 9) CalcTest::testCalc with data set #11 (7, 8, '/', 15) Failed asserting that 0 matches expected 15. /PATH/CalcTest.php:12 FAILURES! Tests: 12, Assertions: 12, Failures: 9.データセットごとにtestCalc()メソッドが実行されていますね!
テストメソッドであるtestCalc()メソッドの直前に@dataProvider numberProvider
と記述しましたが
これがデータプロバイダとしてメソッドを使うための指示になっているので書き忘れ厳禁データプロバイダメソッドの
numberProvider()
メソッドはデータ配列かIteratorインターフェイスを実装したオブジェクトを返すように記述してくださいフィクスチャの話
テストを実行するための事前準備をフィクスチャと呼ぶ
PHPUnitには準備用のコードを共有するために
各テストメソッドが実行される前に自動的に実行されるsetUp()
メソッドや
各テストメソッドが実行された後に自動的に実行されるtearDown()
メソッドがあるプライベートメソッドのテスト
ReflectionMethod
クラスを使う
テストケースを記述するクラスはテストするクラスとは別なので
プライベートメソッドをそのままテストすることができない
そこでReflectorMethod
クラスを使うと外部からアクセス可能なように書き換えてテストしてくれるらしい
めっちゃ便利$r = new ReflectionMethod('テスト対象のクラス', 'テスト対象のメソッド'); $r->setAccessible(true); $test = $r->invoke('テスト対象のクラスのインスタンス');こんな感じ
ReflectionMethodのインスタンスを作成してメソッドのアクセス権を書き換えて
テスト対象のメソッドを呼び出して結果を取得してるーCalcTest.php//@dataProvider numberProvider public function testCalc() { $r = new ReflectionMethod('Calc', 'calc'); $r->setAccessible(true); $test = $r->invoke(new Calc(1, 2)); $expected = 3; $this->assertEquals($expected, $test); }実行結果はこんな感じー
. 1 / 1 (100%) Time: 22 ms, Memory: 4.00 MB OK (1 test, 1 assertion)データベースのテスト方法は長くなるのでまた次の機会にまとめられたらなと思いますー
テストのカバー率やSeleniumを使ってブラウザテストもできるみたいなので
それも合わせてまとめられたらなと思ってますー
- 投稿日:2020-09-25T18:17:56+09:00
【ポエム】Laravelのバリデーションルールの指定方法について考える
今回は ポエム です。技術的には全然高度なお話ではなく、ただ、気持ち悪かったのをどうにかしたかったというお話です。ポエムが苦手な方は「戻る」ボタンを押すことをオススメします。
前提
- PHP 7.4.9
- Laravel 8.5.0
3行でわかるまとめ
Laravel のバリデーションルールの指定方法が気持ち悪い(とくにクラス定数を使ったとき)。
いろいろ試してみたが、気持ち悪さを解消できなかった。
自作パッケージを作って、ようやく気持ち悪さを解消できた。クラス定数問題
Laravel では、バリデーションルールは 文字列 で指定します。例えば、
title
属性に「必須入力であること」と「1000文字以下であること」というルールを指定する場合は、次のように書きます。$request->validate([ 'title' => 'required|max:1000', ]);
|
で区切らずに 配列 で指定することもできます。$request->validate([ 'title' => ['required', 'max:1000'], ]);しかし、マジックナンバーは極力回避したいので
1000
を変数にします。PHP の仕様により、次のように文字列の中に変数を埋め込むことができます。$titleMaxLength = 1000; $request->validate([ 'title' => ['required', "max:{$titleMaxLength}"], ]);
$titleMaxLength
は処理の中で変化するものではありません。こういうときは、できれば 定数 にしたいところです。しかし、定数は文字列の中で展開されないため、次のように書いてもうまく動きません。
class TodoController extends Controller { const TITLE_MAX_LENGTH = 1000; public function store(Request $request) { // この書き方では期待通りの動きをしない。 $request->validate([ 'title' => ['required', "max:{self::TITLE_MAX_LENGTH}"], ]); // ... } }もちろん、文字列演算子 を使って、文字列に定数を結合すれば、うまく動きます。
class TodoController extends Controller { const TITLE_MAX_LENGTH = 1000; public function store(Request $request) { // この書き方ならば期待通りの動きをする。 $request->validate([ 'title' => ['required', 'max:' . self::TITLE_MAX_LENGTH], ]); // ... } }このように書くのが定石でしょう。私も実際に仕事でそう書いたことがありますし、それが悪いというつもりは全くありません。
ただ、個人的にはどうしても居心地の悪さを感じるのです。例えば、「10文字以上であること」というルールを追加すると、このようになります。
class TodoController extends Controller { const TITLE_MIN_LENGTH = 10; const TITLE_MAX_LENGTH = 1000; public function store(Request $request) { $request->validate([ 'title' => ['required', 'min:' . self::TITLE_MIN_LENGTH, 'max:' . self::TITLE_MAX_LENGTH], ]); // ... } }随分と横に長くなってしまいました。でも、あらかじめ変数に入れておけば改善することができます。
class TodoController extends Controller { const TITLE_MIN_LENGTH = 10; const TITLE_MAX_LENGTH = 1000; public function store(Request $request) { $titleRules = [ 'required', 'min:' . self::TITLE_MIN_LENGTH, 'max:' . self::TITLE_MAX_LENGTH, ]; $request->validate([ 'title' => $titleRules, ]); // ... } }それでも、個人的にはどうもしっくり来ません。
'max:' . self::TITLE_MAX_LENGTH
という風に文字列結合しないといけないのでしょうか?メソッド化
汚いものには蓋をする。 メソッド化の目的をそのように説明したら、きっと四方八方から石を投げつけられると思います。でも、試して見る価値はあるのではないかと思ったのです。
getConstant()
というメソッドを作り、引数で渡された定数名をもとに、定数の値を取得します。その中で使っているconstant()
(PHP マニュアル)は定数の値を返す標準関数です。定数が見つからなかった場合にE_WARNING
レベルのエラーを発生させ、Laravel では例外が送出されます。1class TodoController extends Controller { const TITLE_MIN_LENGTH = 10; const TITLE_MAX_LENGTH = 1000; public function store(Request $request) { $titleRules = [ 'required', "min:{$this->getConstant('TITLE_MIN_LENGTH')}", "max:{$this->getConstant('TITLE_MAX_LENGTH')}", ]; $request->validate([ 'title' => $titleRules, ]); // ... } public function getConstant($constantName) { return constant('self::' . $constantName); } }たしかに、これは動きます。でも、「いや、そこまでしなくても...」という声が聞こえてきそうです。頑張ったわりに、そこまで見やすくもないですし...
余談1
ちなみに、クラス定数を取得するならば、
ReflectionClass::getConstant()
(PHP マニュアル)を使うこともできます。public function getConstant($constantName) { return (new \ReflectionClass(__CLASS__))->getConstant($constantName); }しかし、定数が見つからなかった場合の動作が
constant()
と異なります。constant()
はE_WARNING
レベルのエラーを発生させます。一方、ReflectionClass::getConstant()
はエラーを発生させないため(FALSE
を返すだけです)、Laravel でも例外になりません。あえてReflectionClass::getConstant()
を使う理由は無いように思いました。23パッケージ化
話が脱線しましたが、そもそも、どこが嫌だったかと言うと、 文字列結合 していることでした。この点をもう少し考えてみます。
'max:1000'
というバリデーションルールは、以下の2つの部分から構成されています。
- ルール名
max
- ルールの引数
1000
この2つを
:
で繋いで1つの文字列にしなければならないところに、そもそも無理があるように思います。素直に、それぞれを分けて指定できるようにすればいいのではないでしょうか?例えば、
addRule(適用対象, ルール名, ルールの引数)
という風に書くことができれば、クラス定数も文字列結合することなく渡すことができます。以下の例では、addRule()
でルールを追加し、format()
で Laravel のバリデータに渡せる配列形式に変換してから、バリデーションを実行しています。class TodoController extends Controller { const TITLE_MAX_LENGTH = 1000; public function store(Request $request) { // title 属性は必須であること。 $rules = ValidationRuleFormatter::addRule('title', 'required') // title 属性は1000文字以下であること。 ->addRule('title', 'max', self::TITLE_MAX_LENGTH) // Laravel のバリデータに合うようにフォーマットする。 ->format(); // バリデーションを実行する。 $request->validate($rules); // ... } }そして、これを Laravel の パッケージ として作ってみました。以下のように composer でインストールすれば、すぐにお使いいただけます(笑)
composer require aminevsky/laravel-validation-rule-formatterおそらく需要は皆無だと思っていますが、本人は長年のモヤモヤが解決して満足しています(自己満足)
おしまい。
余談2
なんだかんだ初めて Laravel のパッケージを作ったのですが、約200行ほどのちゃっちいプログラムだったこともあってか、意外と簡単に作ることができました。4
パッケージ開発については Laravel ドキュメント もありますが、 Laravel Package Development が一番よくまとまっているように感じました。
PSR-4 や、composer で ローカルディレクトリをリポジトリに指定する方法 に触れられるのも、パッケージ開発ならではだと思います。
通常、PHP では
E_WARNING
が発生しても、処理は継続します。しかし、Laravel ではIlluminate\Foundation\Bootstrap\HandleException
のbootstrap()
でerror_reporting(-1)
と設定されているため、全てのエラーと警告が表示されます(PHP マニュアル)。さらにHandleException
クラスのhandleError()
でErrorException
へ変換されるため、例外が引き起こされたように見えるわけです。 ↩コンパイルが無く、実行時にはじめて間違いに気づくことが多い PHP としては、こういう挙動はあまり嬉しくありません。そもそも
ReflectionClass
インスタンスを作るほどのことでも無いように思えますし。 ↩
error_reporting(-1)
に設定している Laravel としては関係ありませんが、そもそもconstant()
もE_WARNING
レベルのエラーを出力するだけで処理が継続するのはいいのか?という疑問はあります。ただし、PHP 8 では RFC: Reclassifying engine warnings が採択されたため、Error
例外が発生するようになるようです。3v4l.org での 動作例 も参照してください。 ↩本来ならば、このくらいのプログラムは1日で完成させないといけないところですが、3日もかかってしまったのは、全く恥ずべきことだと思います。いやテストコードも無く、クラス分けもしていない状態であれば1日目で出来上がっていたのですが、クラス分けで悩んだ時間のなんと長かったことか... しかもあれだけ悩んだわりに、出来上がったものを見ると、自分でも「この程度かよ」と思うレベルでしかない。一応5年以上プログラミングをやっていて、未だにこの程度ですからね。本当に向いていないんだろうな。無職なので、いろいろ求人を見るけど、やっぱりどこもいい会社は求めるレベルが高くて、私みたいな雑魚はお呼びでない。「モダンな環境でやりたいな」とか「魅力的な事業をやっている会社で働きたいな」とか理想は多々あるけれども、ようやくわかったよ。そういうのは能力が無いと得られないものなんだということを。私みたいな能力の無い者に残された道は2つしかない。自分の理想を捨てて働きたくないところで我慢して働くか、潔く退場するか。そんなことばかり考えていると、ときどき、頭がパニックになったり過呼吸を引き起こしたりして(とくに午前中になりやすい)、Qiita すら昨日は1文字も書けず、今日、ようやく勢いで、どうにか1つ書けたわけですね。はぁ... ↩
- 投稿日:2020-09-25T17:33:08+09:00
アリババクラウドECSへのWP-CLIのインストールと正しい権限とユーザーロールの準備
この3部構成のチュートリアルでは、WP-CLIを使用してWordPressの高度な管理を設定する方法を説明します。パート1では、アリババクラウドECS上でのWP-CLIの設定に焦点を当てています。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
Alibaba Cloud Tech Share執筆者のJeff Cleverley著。Tech Shareは、技術的な知識やベストプラクティスをクラウドコミュニティ内で共有することを奨励するAlibaba Cloudのインセンティブプログラムです。
WordPressは、ウェブ上でダイナミックなコンテンツを持つウェブサイトを開発するために使用される最も人気のあるコンテンツ管理システムです。WordPressの人気の多くは、グラフィカル・ユーザー・インターフェース(GUI)による使いやすさに起因しています。WordPressは常に、初心者が簡単に始められるようなパッケージで、充実した機能を提供してきました。
ブログプラットフォームとしての初期の頃から、WordPress はより広く利用されるリソースへと進化し、大規模な E コマースサイトや企業サイト、ソーシャルネットワークなどで利用されることが多くなりました。より本格的な開発者が使用するプラットフォームへの進化の一部として、WordPress の公式コマンドラインインターフェイスである WP-CLI が導入されました。
コマンドラインインターフェイス(CLI)は、自分のマシン上でタスクを実行できるスピードと効率の良さから、開発者の間で長い間人気を博してきました。様々なツールを使って、開発者は生産性を高め、開発プロセスをスピードアップさせてきました。WP-CLI は、WordPress 開発者とサイトメンテナにも同じメリットと効率を提供します。
WP-CLI は、WordPress Foundation の公式サポートプロジェクトであり、独自のサイトや開発者ハンドブックを持っています。すべてのコマンドとツールの完全なリストはここで見つけることができます。
今回は、WP-CLI が提供する高度な WordPress 管理機能を深く掘り下げていく 3 部構成のシリーズの第 1 回目です。このチュートリアルでは、あなたのインスタンスに WP-CLI をインストールし、それが正しく動作するように正しいパーミッションとユーザーロールを準備し、その後、WordPress コンテンツの管理にどのように使用できるかを見ていきます。次のチュートリアルでは、テーマやプラグイン、メディア、ユーザー、データベースの管理など、より高度な機能について掘り下げていきます。最後に、インスタンス全体で数百のサイトを管理したり、カスタムプラグインやテーマの開発をスピードアップしたり、さらには独自のコマンドを作成してカスタム機能を提供するために拡張したりするために、どのように活用できるかをご紹介します。
WP-CLI を効果的に使用することで、広く使用されているいくつかのプラグインを削除することで、WordPress サイトの肥大化を減らすことができることがわかります。
このチュートリアルでは、すでに Alibaba Cloud ECS インスタンスがプロビジョニングされており、その上で 1 つ(または複数)の WordPress サイトが稼働していることを前提としています。
このシリーズでは、私は自分のスーパーユーザ 'new_user' を使い、sudo コマンドを使って 'root' コマンドを発行します。コマンドを実行する際には、私のユーザーを自分のユーザーに置き換えることを忘れないでください。
私はまた、コード例で私のテストドメイン'an-example-domain.com'と'another-example-domain.com'を使用していますが、コマンドを発行するときに私のサイトドメインをあなた自身のものに置き換えることを覚えておいてください。
1. アリババインスタンスにWP-CLIをインストール
SSHでサーバにログインします。
# ssh new_user@an-example-domain.com
wp-cli.phar」PHPアーカイブファイルをダウンロードします。
$curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
では、ファイルが動作しているかどうかを確認してみましょう。
$ php wp-cli.phar —info
ターミナルには、PHP のバージョン、設定ファイル、WP-CLI のインストールに関する情報が表示されているはずです。
php wp-cli.phar' の代わりに 'wp' と入力するだけで WP-CLI を使用できるようにしたいのですが、そのためには PHP アーカイブファイルを実行可能にする必要があります。また、どこからでも 'wp' コマンドにアクセスできるようにしたいので、それを PATH に移動させる必要があります。
この両方を行うには、以下のコマンドを実行します。
$ chmod +x wp-cli.phar $ sudo mv wp-cli.phar /usr/local/bin/wpあなたの端末は以下のようになっているはずです。
【WP-CLI PHPのアーカイブファイルをダウンロードしてテストする】
ここで、同じ WP-CLI の '--info' コマンドを実行して動作していることを確認することができますが、今回は 'wp' のみを使用しています。
$ wp —info
wp-cliの更新情報を確認したい場合は、以下のようにします。
$ wp cli update
あなたの端末は以下のようになっているはずです。
【WPコマンドを使用するためのアーカイブ実行ファイルを作成する】
すべての WP-CLI コマンド
利用可能なすべての WP-CLI コマンドとグローバルパラメーターの完全なリストを取得するには、次のように入力します。
$ wp
或いは
$ wp help
2. WordPressのインストールとユーザー権限の準備
WP-CLIコマンドをユーザーとして発行することになります。このとき、ディレクトリとユーザーグループを用意しておかないと、Webサイトのディレクトリに書き込む必要があるコマンドで問題が発生する可能性があります。
ディレクトリを '/var/www' ディレクトリに変更してください、または WordPress のインストールが含まれているディレクトリ、およびディレクトリとその所有権とパーミッションをリストアップします。
$ cd /var/www $ ls -lあなたのウェブサイトのルートディレクトリが「www-data」ユーザーとグループに属していることがわかるはずです。これはウェブサーバーが実行するユーザーです。
ディレクトリのパーミッションは 'drwxr-xr-x' または似たようなものかもしれませんが、これは0755で、所有者 (www-data) にのみ書き込み権限を与えます。
www-data'グループのメンバーも書き込み権限を持つように、これを'drwxrwxrxr-x' / 775に変更したいと思います。
これを実行してから、以下のコマンドで再びディレクトリをリストアウトします。
$ sudo chmod -R 775 /var/www/an-example-domain.com $ ls -lこれで、ディレクトリのパーミッションが変更されていることがわかるはずです。
【WordPressのディレクトリのパーミッションを775に変更】
あとは、ユーザーが 'www-data' グループのメンバーであることを確認して、WP-CLI コマンドを使ってこれらのディレクトリに書き込むことができるようにするだけです。
$ sudo usermod -a -G www-data new_user
ユーザーがどのグループに所属しているかは、'groups' コマンドで確認できます。
$ groups
あなたの端末はこのようになっているはずです。
【ユーザーがwww-dataグループに入っていることを確認してください】
3. WordPressのコアコマンド
WordPressコアのインストール
WP-CLI は、WordPress コアのインストールと更新を管理するための強力なツールのセットを提供しています。
これを行う前に、バーチャルホストとサイトのルートフォルダと同様に、WordPress のサイトドメインを設定し、WordPress が使用するためのデータベースを作成して空にしておく必要があります。
私はここの別のチュートリアルですべてを詳細に説明しています。
これらは、'--version' と '--locale' パラメータを使用して、異なるバージョンとローカライゼーションの WordPress をダウンロードする機能を含んでいます。
例えば、以下のようになります。
$ wp core download --version=4.8.4 --local=en_GB
WordPress v.4.4.8.4 をダウンロードして、正しい(イギリスの)英語版をダウンロードしてください。
また、「core config」を使って「wp-config.php」ファイルを作成するなどの方法もあります。
$ wp core config --dbname=tutorial --dbuser=new_user --dbpass=new_users_password --dbhost=localhost --dbprefix=tut_
そして、「core install」コマンドを使ってWordPressをインストールします。
$ wp core install --url=an-example-domain.com --title="WP-CLI Tutorials" --admin_user=new_user --admin_password=new_user_admin_password
これであなたのWordPressサイトは、通常のインストールプロセスを経ることなく、立ち上がることができるようになります。WP-CLI を使用してインストールすると、WordPress の「有名な」(彼ら自身がそう言っている場合)5 分間のインストール手順よりもはるかに速いことがわかります。
WordPress コアの更新
WordPressのインストールを最新の状態に保つことは、セキュリティの観点から非常に重要です。
WordPressのバージョンを確認するには、WordPressのファイルやディレクトリが入っているディレクトリにディレクトリを変更して、以下のコマンドを実行します。
$ wp core version
ご覧のように、私の'an-example-domain.com'のWordPressサイトは古く、WordPress 4.8.4のみを実行しており、最新の4.9.1バージョンではありません。
【WP Coreのバージョンを確認 - 4.8.4は最新版ではありません】
【WordPressにはアップデートが必要】です。
WordPress Core を更新する前に、必ずデータベースのバックアップを取るように警告されています。
多くの人がこの重要なステップを実行しないのは、ワークフローから外れてしまうからです。
WP-CLI を使用すると、信じられないほど簡単で高速なので、今は言い訳はできません。
$ wp db export backup.sql
サードパーティのGUIベースのツールを使ってデータベースをエクスポートしたことがある人は、このコマンドの実行と完了の速さに驚くでしょう。
すぐに「Success」のメッセージが表示されます。
【Coreアップデート前のデータベースのバックアップは、これまでになく簡単になりました】
あとはコアのアップデートをして、再度バージョンを確認します。
$ wp core update $ wp core versionあなたの端末では、表示されているはずです。
【WPCLIを使ってWordPressコアの更新を素早く行う】
データベースの更新も簡単にできます。
$ wp core update db
【WordPressデータベースの更新について】
Coreのアップデートに続いて問題が発生しても安心してください...。
また、WordPress を以前のバージョンに戻すのは信じられないほど簡単です。パラメータに「--version」と「--force」を追加するだけです。
$ wp core update -version=4.9 —force
4. WordPressのコンテンツを管理する
投稿やページのリスト化、作成、削除、編集
自分の投稿やページ、その内容を端末から直接管理することができます。おそらく最適なコンテンツ作成方法ではないかもしれませんが、それでも信じられないほど便利です。
これらのコマンドにはパラメータ '--post_type' があり、デフォルトでは '--post_type=post' となっていますが、すべてのコマンドは '--post_type=page' を使用してページを操作することができます。簡潔にするために、'post'コマンドを'--post_type=post'として説明します。
使えるポストの種類をすべてリストアップするには
$ wp post list
新規インストールしたので、IDが1の「Hello World」の投稿しかないので、それを削除してみます。
$ wp post delete 1
そして、再び書き込みをリストアップすると、それがなくなっていることがわかります。
【投稿を一覧にしてから「ハローワールド!」の投稿を削除してください】
【投稿のないチュートリアルサイトのご案内】
タイトル、内容、ステータスにパラメータを指定して、コマンドで投稿とその内容を作成することができます。
$ wp post create --post_title='Your title' --post_content=“Your most interesting post content” --post_status=‘publish;
再度、投稿をリストアップします。
$ wp post list
これで新しい投稿が一覧で見れるようになりました。
【ターミナルに表示されているWP-CLIが作成した記事】の場合
WordPress のテーマやプラグインを開発するときに、テストのためにたくさんの投稿を作成しなければならないことがよくあります。ブラウザやGUIを使った処理は時間がかかりますが、WP-CLIには「post generate」コマンドがあります。
$ wp post generate --count=4
そして、一瞬にして4つの新しい投稿があります。
【WP-CLIを使ってダミーの投稿を生成する】 - 端末で表示する
【WP-CLIを使ってダミーの投稿を生成する】 - ブラウザで見る
バッチを削除するのは簡単で、IDをリストアップするだけでバッチを削除することができます。
$ wp post delete 8 9 10 11
簡単に来て、簡単に行く。
【WP-CLIによる投稿の一括削除について】
システムエディタを使ってWP-CLIで投稿を編集することもできます。先ほど作成した投稿を編集して、新しい内容を追加してみましょう。
$ wp post edit 7
【WP-CLIとシステムエディタを使った投稿の編集について】
あなたの端末はこのようになっているはずです。
【投稿が正常に編集されました】
編集した投稿をブラウザで見る:
【a WP-CLI作成・編集した投稿について】
Post Metaの管理
WP-CLIの「post meta」コマンドを使って、カスタムフィールドを含むメタデータを「追加」することもできます。
ここでは、「post_type」というカスタムメタフィールドを新たに追加し、「tutorial」という値を与えてみましょう。
$ wp post meta add 7 post_type tutorial
そして、'post_type'の値を'get'します。
$ wp post meta get 7 post_type
【WP-CLIでのポストメタの設定と取得】について
また、用語を追加したり、「セット」したりすることもできます。
$ wp post term set 7 category wpcli
そして、それらを「削除」します。
$ wp post term remove 7 category wpcli
【WP-CLIで用語を作成して削除する】
Revisionsの管理
WordPress は、投稿のリビジョンをすべて投稿として Posts テーブルに保存します。これは膨大な量のデータベースの肥大化につながる可能性があります、これらのリビジョンを管理するのに役立つ多くの便利なプラグインがあります。
しかし、WP-CLI を使用すると、それはさらに簡単です。WP-CLI を使えばもっと早く簡単にできるのに、なぜあなたの WordPress サイトに別のプラグインを追加するのでしょうか?
WP-CLI の美しさの一つは、その拡張性にあり、他の開発者は常にその機能を拡張するためにコマンドクックブックやプラグインを開発しています。これらのプラグインの一つが WP Revisions CLI プラグインです。このシリーズの最後には、このようなプラグインで独自のカスタムコマンドを作成することもあります。
プラグインをwp-cliパッケージとしてインストールします。
$ wp package install trepmal/wp-revisions-cli
それはインストールされ、必要な依存関係をインストールするためにcomposterを使用します。
【WP Revisions CLIをWP-CLIのパッケージとしてインストールする】
これで、WordPressの投稿リビジョンをすべてリストアップすることができるようになりました。
$ wp revisions list
【WP Revisions CLIを使用してWordPressのリビジョンを一覧表示する】
私の場合は7つのリビジョンがあります。これらは必要ないと思うので、クリーンコマンドで削除しようと思います。私は '-1' を使ってすべてのリビジョンを削除し、'--post_type=post' ポストリビジョンのみを指定しています。
$ wp revisions clean -1 --post_type=post $ wp revisions list今、私たちは、私のデータベースを肥大化させるリビジョンを持っていないことがわかります。
【すべての投稿リビジョンをクリーンアップ】
を使って「wp_post_revisionss」オプションの値を確認することもできますね。
$ wp revisions status
【WP_POST_REVISIONS】の値を確認してください。
WP Revisions CLI には 'wp revisions dump' コマンドもあり、リビジョンを削除する前に各投稿を照会しないので、クリーンコマンドよりも高速です。コマンドとそのパラメータの完全なリストはここで見ることができます。
次回は、WordPress のインストール、ユーザー、プラグイン、データベースを管理するための便利なコマンドや、多くのサイトを一度にインスタンス上で管理するためのより高度な設定について掘り下げていきます。
シリーズ最終回では、これらのコマンドを再設定して、ローカルマシン上のいくつかのコマンドで、いくつものアリババクラウドECSインスタンスにまたがる何百ものWordPressサイトを管理できるようにしていきます。また、WordPress の開発とデプロイのワークフローで WP-CLI を使用して開発をスピードアップする方法を学び、最後にカスタムコマンドを使って拡張します。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ
- 投稿日:2020-09-25T15:09:09+09:00
[Laravel8]ログイン機能付きでプロジェクトを作成するまで
- composerでプロジェクトを作成する
- Jetstreamをインストールする
- LivewireかInertiaのどっちかをインストールする
- ビルドする
- データベースを作る
- .envファイルでデータベースを変更する
- マイグレーションする
環境:XAMPP for Windows, Laravel Framework 8.6.0
1. composerでプロジェクトを作成する
まずはcomposerを使ってプロジェクトを作成します。
以下のコードの場合、『your-project』という名前のプロジェクトを作成します。composer create-project --prefer-dist laravel/laravel your-project2. Jetstreamをインストールする
cdコマンドでプロジェクト内に移動したら、Jetstreamをインストールします。
composer require laravel/jetstream3. LivewireかInertiaのどっちかをインストールする
LivewireかInertiaのどっちかを選択してインストールします。
--teams
は、チーム機能を付ける為のオプションです。必要なければ取って良し。php artisan jetstream:install livewire --teamsもしくは、
php artisan jetstream:install inertia --teams4. ビルドする
ビルドします。
npm install && npm run dev5. データベースを作る
私の場合、今回XAMPPを使っているので、XAMPPでサクッとデータベースを作っておきます。
6. .envファイルでデータベースを変更する
.envファイルのデータベース名を忘れずに変更しておきます。
.envDB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=your_project ←ここ。 DB_USERNAME=root DB_PASSWORD=7. マイグレーションする
マイグレーションします。
php artisan migrateすると、以下画像のように8個のテーブルが入った状態で出来上がります。
artisanコマンドでサーバ起動後にトップページを確認すると、以下画像のように右上にLoginとRegisterが表示されます。
php artisan serve以上です。
参考サイト:
https://jetstream.laravel.com/1.x/installation.html
https://blog.capilano-fw.com/?p=7827
- 投稿日:2020-09-25T14:55:18+09:00
PHP Laravel 6 おすすめ映画投稿サイト作成過程 8:ジャンルタグ追加編(後編)
controllerとviewファイルの作成
recommendsのviewファイルを複製して使用しました。
他のviewファイルも同様です。recommend/resources/views/tags/create.blade.php@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">{{ __('Login') }}</div> <div class="card-body"> <form method="POST" action="{{route('tags.store')}}"> @csrf <table> <thead> <tr> <th>タグ</th> </tr> <tr> <th><input type="text" name='title'></th> </tr> </thead> </table> <button type="submit">登録</button> <a href="{{route('recommends.index')}}">一覧に戻る</a> </form> </div> </div> </div> </div> </div> @endsection
- 投稿日:2020-09-25T13:38:48+09:00
PHP Laravel 6 おすすめ映画投稿サイト作成過程 8:ジャンルタグ追加編(前編)
ジャンルタグの追加
映画のジャンルをタグで分けられるようにします
必要なファイルの作成
※-a はallオプション
$ php artisan make:model Modesl/Tag -aマイグレーションファイルの設定
タグは以下の5種類にしますが、いずれもタイトルカラムの一つとなります。
よって、追加するのはタイトルカラムのみです。タグ:SF アクション コメディ ドキュメンタリー サスペンス
recommend/database/migrations/2020_09_25_124109_create_tags_table.phppublic function up() { Schema::create('tags', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('title'); $table->timestamps(); }); }初期データの作成
次に、以下の要領でタグを作成します。
recommend/database/seeds/RecommendTagSeeder.php<?php use Illuminate\Database\Seeder; use App\Models\Tag; class RecommendTagSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { Tag::create([ 'title' => 'SF', 'title' => 'アクション', 'title' => 'コメディ', 'title' => 'ドキュメンタリー', 'title' => 'サスペンス', ]); } }データベースの作成
$ php artisan migrateシーダの実行
オートローダを再生成します。
$ composer dump-autoloadシーダーを読み込みます。
今回は読み込むシーダーを指定するため、以下のようにします。
なお、指定しない場合はDatabaseSeederクラスが実行されます。$ php artisan db:seed --class=RecommendTagSeeder
- 投稿日:2020-09-25T12:23:47+09:00
PHP Laravel 6 おすすめ映画投稿サイト作成過程 7:ルートの制限編
ルートの制限
レート制限
Laravelには、ルートにレート制限をかける便利なミドルウェアが用意されています。
今回は、ゲストと認証ユーザー別のレート制限をかけて、ログインしていないとRecommendContorollerのページに遷移できないようにしてみました。recommend/app/Http/Controllers/RecommendController.phpAuth::routes(); Route::middleware('auth:api', 'throttle:60,1')->group(function () { Route::resource('recommends', 'RecommendController'); Route::get('/', 'RecommendController@index'); });誤って Auth::routes(); を制限下に置かないようにしましょう。
以下のようにしてしまうと、ログインページにも遷移できなくなってしまいます。recommend/app/Http/Controllers/RecommendController.php//このように書いてはいけません Route::middleware('auth:api', 'throttle:60,1')->group(function () { Auth::routes();//遷移できません Route::resource('recommends', 'RecommendController'); Route::get('/', 'RecommendController@index'); });
- 投稿日:2020-09-25T11:58:27+09:00
Laravel/ui のインストール
インストール
Laravel 6 からcssフレームワークが分離したため、別にダウンロードが必要です。
laravel/uiのダウンロード
"1.x" で最新版がインストールされますので、必ず入力しましょう。
$ composer require laravel/ui "1.x" --dev最初、以下のコマンドでダウンロードしたため、スカフォールド生成時にエラーが発生しました。注意してください。
$ composer require laravel/ui:^1.0 --dev //最新版ではないのでエラーを吐きます注意してください。基本的なスカフォールドを生成
ui系
$ php artisan ui bootstrap $ php artisan ui vue $ php artisan ui reactautu系
Reactで実装する場合$ php artisan ui bootstrap --auth $ php artisan ui react --authVueで実装する場合
$ php artisan ui bootstrap --auth $ php artisan ui vue --authCSSの出力
JavaScriptの出力$ npm install $ npm run dev
- 投稿日:2020-09-25T11:39:07+09:00
PHPUnitでスローされた例外をテストする
結論
以下のように書こう?
/** * @test * @return void */ public function insertHoge_異常_{エラー内容}() { // スローを期待する例外の内容 $this->expectException(例外クラス); $this->expectExceptionMessage(例外メッセージ); $param = 不正な値; // 例外をスローするテスト対象メソッド $this->reportService->insertHoge($param); }事例
/** * @test * @return void */ public function addRecord_異常_外部キー不正() { $this->expectException(Exception::class); $this->expectExceptionMessage('a foreign key constraint fails'); $id = 'invalidId'; $this->reportService->insertHoge($id); }Tips
expectExceptionMessage()
による例外メッセージ検証は、部分一致で判定できる- timestampの値を観点にしないテスト等、
観点に含まれない無いが実行タイミングによって変化する値を含むエラーメッセージの検証を行う場合は便利例)
上記事例のテスト実行時に返却される例外メッセージ全文'SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`hoge_db`.`hoge_table`, CONSTRAINT `user_id_foreign` FOREIGN KEY (`id`) REFERENCES `users` (`id`)) (SQL: insert into `hoge` (`id`, `updated_at`, `created_at`) values (0, 2020-09-25 11:31:05, 2020-09-25 11:31:05))'
- 投稿日:2020-09-25T10:05:52+09:00
PHP: コロン構文(初心者向け)
if
while
for
foreach
switch
に関する別の構文がコロン構文です。基本的な考え方
各構造において開き波括弧をコロン
:
、閉じ波括弧をそれぞれendif;
,endwhile;
,endfor;
,endforeach;
,endswitch;
に変更するのが コロン構文の基本的な形式となります。sample_通常使わない形ですが、コロン構文の基本形はこうなります。<?php if ($a == 5): echo 'aは5に等しい'; else: echo 'aは5と等しくない'; endif; ?>タグとコロン構文の融合(重要)
if 文(公式)
sample_if<?php if ($a == 5) { echo 'aは5と等しい'; } else { echo 'aは5と等しくない'; } ?> コロン構文 <?php if ($a == 5): ?> <?= 'aは5に等しい'; ?> <?php else: ?> <?= 'aは5と等しくない'; ?> <?php endif ?>foreach 文(公式)
sample_foreach<?php $users = [0 => ['name' => 'ichiro'], 1 => ['name' => 'jiro'], 2 => ['name' => 'saburo'], //最後のカンマはあってもなくても可(PHP5.4~) ]; foreach ($users as $user) { echo $user['name'] . '<br>'; } ?> コロン構文1 <?php foreach ($users as $user): ?> <?= $user['name'] . ','; ?> <?php endforeach ?> //-> ichiro,jiro,saburo, コロン構文2: foreachとif <?php foreach ($users as $user): ?> <?php if ($user['name'] == 'jiro'): ?> <?= $user['name']; ?> <?php endif ?> <?php endforeach ?> //-> jiroswitch 文(公式)
sample_switch<?php $user = 'ichiro'; switch ($user) { case 'ichiro': echo 'イチロー'; break; case 'jiro': echo 'ジロー'; break; } //-> イチロー ?> コロン構文: インデントを入れると無効なコードになる <?php switch ($user): ?> <?php case 'ichiro': ?> <?= 'イチロー'; ?> <?php break; ?> <?php case 'jiro': ?> <?= 'ジロー'; ?> <?php endswitch ?> //-> イチローwhile 文(公式): 参考
sample_while_コロン構文<?php $i = 0; ?> <?php while ($i <= count($users) - 1): ?> <?= $i . ':' . $users[$i]['name'] . ','; ?> <?php $i++; ?> <?php endwhile ?> //-> 0:ichiro,1:jiro,2:saburo,for 文(公式):参考
sample_for_コロン構文<?php for ($i = 0; $i <= count($users) - 1; $i++): ?> <?= $i . ':' . $users[$i]['name'] . ','; ?> <?php endfor ?> //-> 0:ichiro,1:jiro,2:saburo,endの後のセミコロンについて
<?php endif ?>
or<?php endif; ?>
??
公式を眺めているとなし
かな?と思いますが、統一感があればどちらでもいいと思いますセミコロンコロン構文の基本形 <?php if ($a == 5): ---- endif; //-> セミコロンあり ?> タグと融合している形 <?php if ($a == 5): ?> ---- <?php endif ?> //-> セミコロンなし(どちらでも)注: できるだけ短く記述するために、ショートタグ
<?=
を使っています。
<?=
は<?php echo
の省略形です。LGTMお願いします!
モチベーションがあがります!
- 投稿日:2020-09-25T00:48:24+09:00
Laravel 乱数の生成
目的
- Laravelで桁数を指定した乱数の生成方法をまとめる
例
下記のようにヘルパ関数を用いて乱数生成する。
Str::random(生成桁数);本処理はPHPのrandom_bytes関数を使用して乱数を生成している。
余談であるがPHPのrandom_bytes関数が使用する不規則性のソースはOSやプラットフォームによって異なっているらしい。どれも使えないとき(例外時)は基底クラスを投げるらしい。
- Windows: CNG-API
- Linux: getrandom(2)
- その他: /dev/urandom # 具体例
30桁の乱数を生成し
$str
に格納する処理を下記に記載する。$str = Str::random(30);参考文献
- 投稿日:2020-09-25T00:04:34+09:00
[PHP]PDOでDBへ接続する時に便利なクラス
PHP開発をしていると、絶対にデータベースに接続することは一度はあるはずです。今回はそんなDBへの接続をお手軽にするメソッドを紹介します。
PDOとは
PDOとは、PHP Data Objectの略称で、ナウいPHPではこのクラスを使ってデータベースに接続しています。PDOを正しく使っていればある程度SQLインジェクション対策にもなるため、セキュリティ観点からもWEB上に公開するアプリケーションはこのPDOを使うことが推奨されます(多分)。
DBへの接続を簡素にするコード
setting.phpdefine("DEV", $_SERVER['SERVER_NAME'] === "localhost" ? true : false); //開発環境か否か $_ = function(string $str): string{return $str;}; //ヒアドキュメント用 class Connect { //三項演算子を使って開発環境と本番環境でDSNを出し分ける const HOST = DEV ? "localhost" : "xxx.example.net"; const USER = DEV ? "root" : "server_admin_name"; const PASS = DEV ? "root" : "server_password"; const UTF = "utf8"; public function __construct($dbName) { global $_; $dsn = "mysql:dbname={$dbName};host={$_(self::HOST)};charset={$_(self::UTF)}"; try{ $pdo = new PDO($dsn, self::USER, self::PASS, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES {$_(self::UTF)}"]); }catch(Exception $e){ echo "Connection Error"; die(); } $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $this->dbh = $pdo; } }実際に接続して、値を取得するときは以下のようにする
$con = new Connect("database_name"); $pdo = $con->dbh; //プリペアドステートメントなしで値を取得する $stmt = $pdo->query("SELECT id, name FROM TABLE1;"); while($item = $stmt->fetch(PDO::FETCH_ASSOC)){ echo "id:{$item['id']} name:{$item['name']}"; } //IDが$xのnameを取得する場合 $stmt = $pdo->prepare("SELECT name FROM TABLE1 WHERE id = ? LIMIT 1;"); $stmt->execute([$x]); $item = $stmt->fetch(PDO::FETCH_ASSOC); echo "idが{$x}のnameは{$item['name']}です。";