20210411のPHPに関する記事は9件です。

公式PHPライブラリでStripe決済を試してみる

こんにちは。 めちゃくちゃ簡単に決済システムが構築できてしまうStripe。APIが豊富で、凝りたければいくらでも作り込めるのが魅力です(終わりなき旅になってしまいますが……)。 とりあえず触りだけ触ってきました。 ライブラリのインストール https://github.com/stripe/stripe-php PHP用ライブラリはここにあります。適当にダウンロードしてインストール。 お試し用コード //Stripe API $stripe = new MyStripeApi(); $stripe->sub = $sub; $stripe_response = $stripe->getSubs(); $subには、Stripeで管理されている定期支払い(いわゆるサブスク)IDが入っているという前提です。次回詳しく説明します。 <?php /* Author: toyohama Version: 0.1.3 */ require_once(dirname(__FILE__) . '/'. 'stripe-php/init.php'); class MyStripeApi { public $sub = ''; public function __construct() { \Stripe\Stripe::setApiKey("sk_test_xxxxxx................."); } public function getSubs(){ if ( strlen( $this->sub ) <= 0 ) { return "ng"; } $StripeSubscription = \Stripe\Subscription::retrieve($this->sub); return $StripeSubscription; } public function doCancel(){ if ( strlen( $this->sub ) <= 0 ) { return "ng"; } $StripeSubscription = \Stripe\Subscription::retrieve($this->sub); $StripeSubscription->cancel(); return $StripeSubscription; } } stripe-php以下にまるっと置いてある前提です。 setApiKeyに、Stripe側で作っておいたシークレットキーをセットします。ベタ書きしていますが、本当はきちんとどっかで管理すべきです、当然ですが。 \Stripe\Subscription::retrieveで、現在の定期支払いの状態を取得できます。公式のこのあたりを見てもらうとわかりますが、めっちゃたくさん返ってきます。 上記のdoCancel()の中でやっていますが、この状態でcancel()を呼ぶと、その定期支払いをキャンセル(終了)できるようです。あっけなさすぎて逆に不安になるレベル……。なんらかの形で結果が取得できるとは思います(調べきれていない)。 $stripe = new \Stripe\StripeClient( 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' ); $stripe->subscriptions->cancel( 'sub_AgOem0qdyCowxn', [] ); 公式に掲載されていたキャンセル処理がこちら。こっちのほうがすっきりしてますね。 他にも、updateやall、createといった操作ができるみたいです。お手軽すぎる。 まとめ 本当にさわりだけですが、自分のサイトやブログに自力でカスタマイズした決済機能をつけたい、というようなときに一番扱いやすいのではないでしょうか。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初学者がLaravelを学び始める2(ルーティング)

サーバーを起動させる php artisan serve このコマンドによってサーバーを起動させることができます。 ルート情報を追加する(htmlを表示する) 次にルーティングを設定していきます。 仮にweb.phpに以下のルート情報を記述した場合は web.php Route::get('/', function () { return view('welcome'); }); 省略 Route::get('hello',function () { return '<html><body><h1>おはよう</h1><p>これは見本です!!</p></body></html>'; }); http ://localhost:8000/helloにアクセスすると web.phpで記述したhtmlを表示することができる。(おはよう これは見本です!!が表示される)これが追加したルート情報による表示である。 ヒアドキュメントを使う ヒアドキュメントはPHPで長文テキストを記述するときに使われるものです。演算子を使って、リスト内に直接記述されたテキストをまとめて変数などに代入できます。 Route::get('/', function () { return view('welcome'); }); 省略 $html = <<<EOF <html> <head> <title>Hello</title> <style> body {font-size:16pt; color:#999; } h1 { font-size:100pt; text-align:right; color:#eee; margin:-40px 0px -50px 0px; } </style> </head> <body> <h1>Hello</h1> <p>This is sample page.</p> <p>これは、サンプルで作ったページです。</p> </body> </html> EOF; Route::get('hello',function () use ($html) { return $html; }); /helloにアクセスするとある程度デザインされた形で表示されます。 こんな感じです↓ このようにヒアドキュメントを使ってhtmlのソースコードをきちんと用意できればroute::getだけである程度のウェブページを作ることはできます。 もちろんこれはこういったこともできるということであって本格的なウェブページを作る場合には別の方法が用意されています。 大切なことはroute::getの役割としてreturnする関数を用意すればそのままウェブページが表示されるという仕組みを理解することです。 ルートパラメーターの利用 route::getでは、アクセスするときにパラメーターを設定して値を渡すことができる. 書き方としては以下のようになる Route::get('/〇〇/{パラメーター}',function($受け取り引数){.....}); 第一引数のアドレス部分に{パラメーター}という形でパラメーターを渡しています。 これによって{パラメーター}に指定されたテキスト部分がパラメーターとして取り出せるようになります。 第二引数の関数ではパラメーターの値を受け取る変数として引数を用意しておきます。 ここは{パラメーター}と同じ名前である必要はありません。{パラメーター}で指定したパラメーターはそのまま関数の引数に渡されます。 パラメーターは複数用意することもでき、関数の引数を複数用意することによって値を受け取ることができます。 パラメーターを利用する 以下のコードに修正する。 今回はヒアドキュメント内に変数を埋め込んで使用するためRoute::getの第二引数に用意するクロージャ(無名関数)ないにヒアドキュメントを移動している。 Route::get('hello/{msg}',function ($msg) { $html = <<<EOF <html> <head> <title>Hello</title> <style> body {font-size:16pt; color:#999; } h1 { font-size:100pt; text-align:right; color:#eee; margin:-40px 0px -50px 0px; } </style> </head> <body> <h1>Hello</h1> <p>{$msg}</p> <p>これは、サンプルで作ったページです。</p> </body> </html> EOF; return $html; }); この状態でhttp://localhost:8000/hello/this_is_test にアクセスした場合 「this_is_test」の部分がパラメーターとして取り出されwebページに表示される。 解説していくと第一引数'hello/{msg}'とhello/の後に{msg}というパラメーターがあり、第二引数のグロージャの引数に$msgがあるため{msg}の値が$msg引数に渡されることになる。 今回は一つのパラメーターだけを用意したが複数になってもやることは同じです。 Route::get('hello/{id}{pass}'),function($id,$pass){省略}); このように書いた場合$idと$passの二つのパラメーターを引数として利用できるようになる。 必須パラメーターと任意パラメーター 今までのパラメーターは基本的に必須パラメーターとなっています。必須パラメーターは指定せずにアクセスするとエラーになってしまいます。用意されているルートパラメーターは必ずつけてアクセスしなければなりません。 パラメーターをつけなくともアクセスするためには任意パラメータを使います。 任意パラメータとは名の通り「任意につけて利用できるパラメータ」です。 第一引数のパラメータの末尾に?をつけることで使用できます。 第二引数の関数では、値が渡される仮引数にデフォルト値を指定し引数が渡されなくとも処理ができるようにしておきます。 今までのコードを任意パラメータを使って一行目を以下のように書き換えると パラメータをつけずにアクセスしたためデフォルトのno message.が表示されています。 Route::get('hello/{msg?}',function ($msg='no message.') { $html = <<<EOF <html> <head> <title>Hello</title> <style> body {font-size:16pt; color:#999; } h1 { font-size:100pt; text-align:right; color:#eee; margin:-40px 0px -50px 0px; } </style> </head> <body> <h1>Hello</h1> <p>{$msg}</p> <p>これは、サンプルで作ったページです。</p> </body> </html> EOF; return $html; });
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPで言うセッションとクッキーの違い

聞かれたときにパッと答えられなかったので備忘録として PHPで言うセッション($_SESSION)とクッキー($_COOKIE)の違いは セッションとは PHP公式の説明だと PHPのセッションサポート機能は、複数回のアクセスを通じて特定のデータを保持する手段を実現するものです。 Web サイトの訪問者にはセッションIDというセッションIDと呼ばれるユニークなIDが割りつけられ ます。このIDは、ユーザー側にクッキーとして保存するか、または、URL に埋め込みます。 要は「セッションID」をクッキーorURLに持たせて、その「セッションID」をキーにサーバーにデータを保存しています。(デフォルトだと「セッションID」はクッキーに持たせている) MAMPのphp.iniの設定では、下記にセッションのデータが残っているはずです session.save_path = /Applications/MAMP/tmp/php 「セッションID」はデフォルトで「PHPSESSID」としてクッキーに保存しているので、試しに下記を実行するとアクセスしているユーザーのセッションが全部消えるはずです(消えると言うより取得できなくなる。サーバー側に残っちゃう) setcookie('PHPSESSID', ''); セッションの詳しい設定は下記に載っています https://www.php.net/manual/ja/session.configuration.php クッキーとは PHP公式の説明だと PHP は、HTTP クッキー(Cookie)を完全にサポートします。 クッキーは、リモートブラウザに文字列データを保存したり、 再訪するユーザーを特定したりする機構です。 要はHTTPクッキーそのものです。HTTPクッキーはブラウザ側にキーと値のペアで保存されるデータです。 HTTP Cookie (ウェブ Cookie、ブラウザー Cookie) は、サーバーがユーザーのウェブブラウザーに送信する小さなデータであり、ブラウザーに保存され、その後のリクエストと共に同じサーバーへ返送されます。 https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies まとめ セッションはブラウザ+サーバー側で持ってるデータ クッキーはブラウザ側で持ってるデータ ただしこの話はPHPの話であって 一般的に言われる「セッション」もこうとは限らないです! 一般的に言われる「クッキー」はHTTPクッキーのことと思ってもらっても大丈夫です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gilded Rose Refactoring Kata in PHP

この記事について こちらのリポジトリにて公開されている、リファクタリングやってみようシリーズのうちの1つです。 様々な言語での実装があり、喜ばしいことに PHP もありましたので、やってみました。 はじめに Kata とは 日本の武道における「形」(あるいは「型」)が語源(というかそのまま英語になった)で、 「練習」のような意味になったと思われます。 つまり、Kata に取り組むことで、プログラミング(今回の場合はリファクタリング)の訓練になるということです。やっていきましょう。 概要 架空の宿屋で販売している商品の品質状態に関するお題です。既存のコードが動いていますが、今回新たに商品を追加することになったので、それに先立ってリファクタリングしましょう、という趣旨です。 詳しくは要件仕様書がありますので、そちらをご覧ください(日本語がある!)。 環境 PHP: 7.4.16 (依存ライブラリのエラーで 8.0 は使えなかったです) 導入 こちらのインストラクションに従ってインストールしてください。 https://github.com/emilybache/GildedRose-Refactoring-Kata/blob/main/php/README.md やること GildedRoseTest を実装してテストを通す リファクタリングする Conjured アイテムのためのテストを書く Conjured アイテムを追加する 1. GildedRoseTest を実装してテストを通す 仕様書と既存のコードを読みながらテストを書いていきます。 <?php declare(strict_types=1); namespace Tests; use GildedRose\GildedRose; use GildedRose\Item; use PHPUnit\Framework\TestCase; class GildedRoseTest extends TestCase { /** * @param Item $item * @param array $expected * @dataProvider dataUpdateQuality */ public function testUpdateQuality(Item $item, array $expected): void { $items = [$item]; $gildedRose = new GildedRose($items); $gildedRose->updateQuality(); $this->assertSame($expected['sell_in'], $items[0]->sell_in); $this->assertSame($expected['quality'], $items[0]->quality); } public function dataUpdateQuality(): array { return [ '一般的なアイテム,両方の項目の値は1小さくなります' => [ 'item' => new Item('+5 Dexterity Vest', 1, 1), 'expected' => [ 'sell_in' => 0, 'quality' => 0, ], ], '一般的なアイテム,Quality値は決してマイナスにはなりません' => [ 'item' => new Item('+5 Dexterity Vest', 1, 0), 'expected' => [ 'sell_in' => 0, 'quality' => 0, ], ], '一般的なアイテム,販売するための残り日数が無くなると、Quality値は2小さくなります' => [ 'item' => new Item('+5 Dexterity Vest', 0, 2), 'expected' => [ 'sell_in' => -1, 'quality' => 0, ], ], 'Aged Brie,日が経つほどQuality値が上がっていきます' => [ 'item' => new Item('Aged Brie', 1, 49), 'expected' => [ 'sell_in' => 0, 'quality' => 50, ], ], 'Aged Brie,Quality値は50以上にはなりません' => [ 'item' => new Item('Aged Brie', 1, 50), 'expected' => [ 'sell_in' => 0, 'quality' => 50, ], ], 'Sulfuras,販売されたり、Quality値が低下したりすることはありません' => [ 'item' => new Item('Sulfuras, Hand of Ragnaros', 1, 80), 'expected' => [ 'sell_in' => 1, 'quality' => 80, ], ], 'Sulfuras,販売されたり、Quality値が低下したりすることはありません(-1であっても)' => [ 'item' => new Item('Sulfuras, Hand of Ragnaros', -1, 80), 'expected' => [ 'sell_in' => -1, 'quality' => 80, ], ], 'Backstage pass,SellIn値が近づくにつれてQuality値が上昇します' => [ 'item' => new Item('Backstage passes to a TAFKAL80ETC concert', 11, 10), 'expected' => [ 'sell_in' => 10, 'quality' => 11, ], ], 'Backstage passes,10日以内になると毎日2上がります' => [ 'item' => new Item('Backstage passes to a TAFKAL80ETC concert', 10, 10), 'expected' => [ 'sell_in' => 9, 'quality' => 12, ], ], 'Backstage passes,5日以内になると毎日3上がります' => [ 'item' => new Item('Backstage passes to a TAFKAL80ETC concert', 5, 10), 'expected' => [ 'sell_in' => 4, 'quality' => 13, ], ], 'Backstage passes,コンサート終了後には0になります' => [ 'item' => new Item('Backstage passes to a TAFKAL80ETC concert', 0, 10), 'expected' => [ 'sell_in' => -1, 'quality' => 0, ], ], 'Backstage passes,Quality値は50以上にはなりません' => [ 'item' => new Item('Backstage passes to a TAFKAL80ETC concert', 5, 48), 'expected' => [ 'sell_in' => 4, 'quality' => 50, ], ], ]; } } 仕様書に書かれている文言を使ってテストケースをつくっていきます。足りないと思ったら追加していきましょう。 実はこのプロジェクトには、一般的に使われる PHPUnit の他に、 ApprovalTests というライブラリが使われていて(初めて知りました)、このライブラリ用のテストシナリオがあらかじめ提供されています。 前述の PHP 8 でのエラーはこのライブラリが原因で、プルリクエストも出ていますが放置されてしまっています。PHP 8 でやりたい場合は、tests/ApprovalTest.php とこのライブラリへの依存を削除してください。 2. リファクタリングする わりと長いので全文引用は避け、リファクタリングの方針に関する箇所のみ抜粋します。 方針としては、 - ループ内の処理を1行にする - 各アイテムをクラスにする といったところでしょうか。 ループ内の処理を1行にする public function updateQuality(): void { foreach ($this->items as $item) { if ($item->name != 'Aged Brie' and $item->name != 'Backstage passes to a TAFKAL80ETC concert') { if ($item->quality > 0) { if ($item->name != 'Sulfuras, Hand of Ragnaros') { $item->quality = $item->quality - 1; // ....... のっけから if 文のネストが登場して挑戦的ですが、慌てずごそっと移動しちゃいます。 public function updateQuality(): void { foreach ($this->items as $item) { $this->updateItemQuality($item); } } private function updateItemQuality(Item $item) { if ($item->name != 'Aged Brie' and $item->name != 'Backstage passes to a TAFKAL80ETC concert') { if ($item->quality > 0) { if ($item->name != 'Sulfuras, Hand of Ragnaros') { $item->quality = $item->quality - 1; // ...... 各アイテムをクラスにする 続いてアイテムの名前によって処理を分けている部分をクラスにして、プロパティを更新している箇所を局所化します。 目的は、今後新たにアイテムが追加になったときに(まさにこのあと Conjured アイテムを追加しますが)、他のクラスに影響を及ぼさずに追加できるようにすることです。 ざっと眺めた感じ、既存のコードは思い切って捨てて、仕様書を見ながら新たに書いていったほうが早そうなので、既存のコードは参考程度に留めます。 まず、各アイテムを共通して扱うために interface を用意します。 <?php declare(strict_types=1); namespace GildedRose; interface GildedRoseItem { public function update(): void; } 各々このインタフェースを実装していきますが、全部載せるのもアレなので、 Aged Brie だけ載せます。 <?php declare(strict_types=1); namespace GildedRose; class AgedItem implements GildedRoseItem { private Item $item; public function __construct(Item $item) { $this->item = $item; } public function update(): void { $increase = 1; if ($this->item->sell_in <= 0) { $increase = 2; } $this->item->quality = min(50, $this->item->quality + $increase); $this->item->sell_in--; } } 本当なら、 Item クラスはバリューオブジェクト的にイミュータブルにしたかったんですが、Item クラスと updateQuality メソッドに手を加えてはいけない、という制約がありますので、大人しく直にプロパティを上書きしていきます。 悩ましいのは Item::sell_in の扱いで、 Sulfuras 以外のアイテムは共通のルールで変化しますので、これを共通化するべきでしょうか。これは「販売するための残り日数」ですから、今後このルールが変わる可能性は低そうと判断し、各クラスでそれぞれ行うようにしました。 各アイテムの実装ができたら、次はファクトリクラスをつくります。 <?php declare(strict_types=1); namespace GildedRose; class ItemFactory { public function factory(Item $item): GildedRoseItem { if ($item->name === 'Aged Brie') { return new AgedItem($item); } if ($item->name === 'Backstage passes to a TAFKAL80ETC concert') { return new BackstagePassItem($item); } if ($item->name === 'Sulfuras, Hand of Ragnaros') { return new LegendaryItem($item); } return new GeneralItem($item); } } 名前に応じて生成するクラスを分けます。これで GildedRose::updateQuality() の中身を置き換えます。 public function updateQuality(): void { $factory = new ItemFactory(); foreach ($this->items as $item) { $factory->factory($item)->update(); } } ItemFactory::factory() を ItemFactory::__invoke() として、以下のようにしてもいいかもしれないです。 public function updateQuality(): void { $factory = new ItemFactory(); foreach ($this->items as $item) { $factory($item)->update(); } } テストを実行して、すべてのテストケースが通ることを確認して、次のステップに移ります。 3. Conjured アイテムのためのテストを書く テストファーストでやっていきます。仕様書を読むと "Conjured"アイテムは、通常のアイテムの2倍の速さで品質が劣化します。 とあり、現状通常のアイテムは、販売期限前であれば 1 、販売期限後は 2 ずつ劣化しているので、それぞれ 2,4 ずつということになります。 以下のようにテストケースを追加しました。 'Conjured,両方の項目の値は2小さくなります' => [ 'item' => new Item('Conjured Mana Cake', 1, 2), 'expected' => [ 'sell_in' => 0, 'quality' => 0, ], ], 'Conjured,Quality値は決してマイナスにはなりません' => [ 'item' => new Item('Conjured Mana Cake', 1, 0), 'expected' => [ 'sell_in' => 0, 'quality' => 0, ], ], 'Conjured,販売するための残り日数が無くなると、Quality値は4小さくなります' => [ 'item' => new Item('Conjured Mana Cake', 0, 4), 'expected' => [ 'sell_in' => -1, 'quality' => 0, ], ], テストが失敗することを確認します。 % composer test ✘ 1 > phpunit PHPUnit 8.5.4 by Sebastian Bergmann and contributors. .............F.F 16 / 16 (100%) Time: 30 ms, Memory: 4.00 MB There were 2 failures: 1) Tests\GildedRoseTest::testUpdateQuality with data set "Conjured,両方の項目の値は2小さくなります" (GildedRose\Item Object (...), array(0, 0)) Failed asserting that 1 is identical to 0. /Users/nunulk/var/projects/private/kata/GildedRose-Refactoring-Kata/php/tests/GildedRoseTest.php:26 2) Tests\GildedRoseTest::testUpdateQuality with data set "Conjured,販売するための残り日数が無くなると、Quality値は4小さくなります" (GildedRose\Item Object (...), array(-1, 0)) Failed asserting that 2 is identical to 0. /Users/nunulk/var/projects/private/kata/GildedRose-Refactoring-Kata/php/tests/GildedRoseTest.php:26 FAILURES! Tests: 16, Assertions: 31, Failures: 2. Script phpunit handling the test event returned with error code 1 tests/approvals/ApprovalTest.testTestFixture.approved.txt も2ずつ減るように修正します。 diff --git a/php/tests/approvals/ApprovalTest.testTestFixture.approved.txt b/php/tests/approvals/ApprovalTest.testTestFixture.approved.txt index a04e48a..4e7237f 100644 --- a/php/tests/approvals/ApprovalTest.testTestFixture.approved.txt +++ b/php/tests/approvals/ApprovalTest.testTestFixture.approved.txt @@ -21,7 +21,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 14, 21 Backstage passes to a TAFKAL80ETC concert, 9, 50 Backstage passes to a TAFKAL80ETC concert, 4, 50 -Conjured Mana Cake, 2, 5 +Conjured Mana Cake, 2, 4 -------- day 2 -------- name, sellIn, quality @@ -33,7 +33,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 13, 22 Backstage passes to a TAFKAL80ETC concert, 8, 50 Backstage passes to a TAFKAL80ETC concert, 3, 50 -Conjured Mana Cake, 1, 4 +Conjured Mana Cake, 1, 2 -------- day 3 -------- name, sellIn, quality @@ -45,7 +45,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 12, 23 Backstage passes to a TAFKAL80ETC concert, 7, 50 Backstage passes to a TAFKAL80ETC concert, 2, 50 -Conjured Mana Cake, 0, 3 +Conjured Mana Cake, 0, 0 -------- day 4 -------- name, sellIn, quality @@ -57,7 +57,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 11, 24 Backstage passes to a TAFKAL80ETC concert, 6, 50 Backstage passes to a TAFKAL80ETC concert, 1, 50 -Conjured Mana Cake, -1, 1 +Conjured Mana Cake, -1, 0 -------- day 5 -------- name, sellIn, quality 4. Conjured アイテムを追加する 前述の「2倍」というルールが生きるのであれば、通常のアイテムが 2 ずつ劣化すると変更があった場合、自動的に 4 ずつ劣化するようになってほしいところです。 なので、通常アイテムのクラス( GeneralItem ) を継承させます。 通常アイテムのクラスは以下のとおり実装しました。 <?php declare(strict_types=1); namespace GildedRose; class GeneralItem implements GildedRoseItem { private Item $item; public function __construct(Item $item) { $this->item = $item; } public function update(): void { $decrease = 1; if ($this->item->sell_in <= 0) { $decrease = 2; } $this->item->quality = max(0, $this->item->quality - $decrease); $this->item->sell_in--; } } ひとまずは継承させずに実装してみます。 <?php declare(strict_types=1); namespace GildedRose\Item; use GildedRose\GildedRoseItem; use GildedRose\Item; class ConjuredItem implements GildedRoseItem { private Item $item; public function __construct(Item $item) { $this->item = $item; } public function update(): void { $decrease = 2; if ($this->item->sell_in <= 0) { $decrease = 4; } $this->item->quality = max(0, $this->item->quality - $decrease); $this->item->sell_in--; } } さて、 Conjured アイテムは通常アイテムの2倍のスピードで劣化することは仕様書に明記されていますが、販売期限を過ぎた場合の劣化値は現状たまたま2倍なだけなので、両者は区別したほうがよさそうです。 親クラス( GeneralItem )に期限前の劣化値と期限後の劣化値を別々に持たせ、子クラスではそれを2倍で初期化するようにします。 GeneralItem.php <?php declare(strict_types=1); namespace GildedRose; class GeneralItem implements GildedRoseItem { protected int $decreaseBeforeSellByDate = 1; protected int $decreaseAfterSellByDate = 2; private Item $item; public function __construct(Item $item) { $this->item = $item; } public function update(): void { $decrease = $this->decreaseBeforeSellByDate; if ($this->item->sell_in <= 0) { $decrease = $this->decreaseAfterSellByDate; } $this->item->quality = max(0, $this->item->quality - $decrease); $this->item->sell_in--; } } ConjuredItem.php <?php declare(strict_types=1); namespace GildedRose; class ConjuredItem extends GeneralItem { public function __construct(Item $item) { parent::__construct($item); $this->decreaseBeforeSellByDate *= 2; $this->decreaseAfterSellByDate *= 2; } } 最後に、Factory に Conjured アイテムを生成する処理を追加します。 ItemFactory.php if ($item->name === 'Sulfuras, Hand of Ragnaros') { return new LegendaryItem($item); } // このブロックを追加 if ($item->name === 'Conjured Mana Cake') { return new ConjuredItem($item); } return new GeneralItem($item); テストを実行します。 % composer test > phpunit PHPUnit 8.5.4 by Sebastian Bergmann and contributors. ............. 13 / 13 (100%) Time: 35 ms, Memory: 4.00 MB OK (13 tests, 25 assertions) おわりに 世の中にはアルゴリズム的な問題は多くありますが、こうしたリファクタリングの問題は少ないので、たまたまこのリポジトリの存在を知ることができてよかったです。60 - 120 分程度でできるボリュームになっているので、興味のある方はぜひトライしてみてください(Emily Bache さんの GitHub には他にも Refactoring Kata があるので、そちらもぜひ)。 間違いや改善点などあれば、コメント欄にてご指摘ください
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MAMP 環境構築 2021

MAMPを導入していきます。 MAMPを使うことで最低限必要なPHP開発環境を簡単にMac環境にインストールすることができます。MAMPは以下の頭文字です。 MacOSX(マックオーエスエックス):OS Apache(アパッチ):Webサーバソフトウェア MySQL(マイエスキューエル):データベース管理システム PHP(ピーエイチピー):Webプログラミング言語 MAMPダウンロードサイトURL 左上のメニューからMAMPを選んでいただくと[↓Free Downroad]というボタンが出てくるので、そちらを押していただくとダウンロードが始まります。 ダウンロードできたら、それを開きます。 そのまま「次へ」と進んでいき、「インストール」をクリック。 途中パスワードや「許可する」など聞かれますが、MAMPは信頼できるソフトウェアなのでOKで大丈夫です。 インストールが完了いたしましたら、インストーラーはもう使わないので「ゴミ箱に入れる」で大丈夫です。 インストールできたら、ファインダーからアプリケーションを開いて「MAMP」を探してください。 すぐ近くに「MAMP PRO.app」がありますが、今回は使わないので気にしないでOKです。 「MAMP」を開くと「MAMP.app」があるので、ダブルクリックでアプリを起動してください。 これから、デフォルトで設定されている「8888番ポート」から「80番ポート」に変更する作業を行います。 MAMP右上の「Start」でサーバーを起動します。 次に、左上の「Preferences」をクリック。 「Ports」タブをクリックして、以下のポート番号に変更してください。 Apache Port:80 Nginx Port:80 MySQL Port:3306 ➡︎ OK 次にタイムゾーンの変更を行います。 まずはMAMPの画面から、PHPのバージョンを確認します。 今回の例では、7.4.12でした。 php.iniを探しましょう。 「アプリケーション」→「MAMP」→「bin」→「php」→「php7.4.12」→「conf」の中にあります。 これをテキストエディタ(今回はVSCodeを使用)で開きましょう。 date.timezoneが時刻の設定をしている場所です。 デフォルトでは世界標準時間になっています。(イギリスのロンドンですね。) これを東京に変えます。 まずはvscode内で、ファイル内検索(「⌘+F」のショートカット)を使って「date.timezone」を検索して下記の一文を見つけましょう。 date.timezone = "Europe/Berlin" これを、下記のように修正します。 date.timezone = "Asia/Tokyo" 最後に、Command + Sで保存しましょう。 まずはHello World!から出力してみます。 index.phpという名前のファイルを「MAMP/htdocs/」内に作成してください。 MAMPはhtdocs内のディレクトリやファイルを監視しています。 そして、そのファイルの中に下記の記述をします。 <?php echo "Hello World!"; ?> ここまで書いて上書き保存をします。 そして、下記のURLにアクセスしてください。 「http://localhost/index.php」 すると、ブラウザ上で表示されたと思います。 以上で環境構築作業は終了です。お疲れ様でした!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Visual Studio Code+VagrantでPHPの開発環境を構築する

はじめに Visual Studio CodeとVagrantでPHPの開発環境を構築する手順についてまとめてみました。 Visual Studio Codeとは? Microsoftが開発しているWindows、Linux、macOS用のソースコードエディタです。 カスタマイズ性が高く、テーマやキーボードショートカット、環境設定を変更できたり、機能を追加する拡張機能をインストールすることができます。 略して「VSCode(ブイエスコード)」と呼ぶこともあります。 Vagrantとは? 仮想環境を構築するためのソフトウェアです。 構成情報を記述した設定ファイル (Vagrantfile) を元に、仮想環境の構築から設定までを自動的に行うことができます。 開発に仮想環境を使用するメリットとは? XAMPPなどをインストールすれば、とても簡単にPHPの開発環境を構築できます。 ただし、1台のPCで複数の開発環境を管理しようと思うと、別の開発環境の設定の影響をうけてしまったりと、思わぬ挙動に困らせられる事があります。 仮想環境を使用すると仮想マシン内で環境を構築するので、PCの環境を汚さずに開発環境を構築することができます。 使わなくなった開発環境の削除は仮想マシンの削除を行うだけでよいので、管理が簡単です。 Vagrantを使用するメリットとは? Vagrantはコマンドを入力して実行するCUIのソフトウェアです。 仮想マシンを立ち上げて、GUIでポチポチ操作してXAMPPをインストールして、、、とGUIで環境構築してもいいのですが、Vagrantなら環境構築を自動化する事ができます。 チームで同一の環境を構築したい場合などは、GUIで環境構築するよりも、処理が自動化できるVagrantが断然便利です。 コマンドで操作できるので、グラフィック操作よりも処理が軽いです。 インストール手順 Windows10 64bit での手順です。 以下からそれぞれのインストーラをダウンロードして、画面の指示に従ってインストールします。 (インストール時のオプションの変更は特に不要で、次へ次へと進んでいけばOKです。) Visual Studio Code https://code.visualstudio.com/Download ※執筆時点の最新Verは VSCodeUserSetup-x64-1.55.1.exe Vagrant https://www.vagrantup.com/downloads ※執筆時点の最新Verは vagrant_2.2.15_x86_64.msi VirtualBox https://www.virtualbox.org/wiki/Downloads ※執筆時点の最新Verは VirtualBox-6.1.18-142142-Win.exe インストールができたら、PCを再起動します。 再起動したら、コマンドプロンプトで以下コマンドを実行し、Vagrantがインストールされている事を確認しましょう。 コマンドプロンプト vagrant -v Vagrantのバージョンが表示されればインストールが出来ています。 仮想マシン構築手順 Visual Studio Code を起動する インストールしたVisual Studio Code をダブルクリックして起動します。 「ファイル」 → 「フォルダーを開く」をクリックし、開発環境を作りたいフォルダを選択します。 今回は「C:\work\test」に開発環境を作りたいと思います。 Vagrant Boxを検索する Vagrant Boxとは、仮想マシンのテンプレートとなるファイルです。 CentOSのBoxを使えば、CentOS環境を構築することができます。 自分でBoxファイルを作成することも可能ですが、すでに公開されているBoxを使えば手っ取り早く環境を構築することができます。 今回はChef社が公開しているBoxを使用してCentOS環境を構築します。 https://app.vagrantup.com/boxes/search 上記のリンクにアクセスし、「bento/centos」で検索します。 Boxは「bento/centos-7.5」を使用します。 bentoというのはユーザ名で、Chef社が公開しているBoxです。 検索結果一覧でBox名をクリックすると、vagrantコマンドが記載されているので、こちらを後で実行します。 ※「bento/centos-7.5」以外のBoxを使用すると、このあとに実行していくコマンドがうまく反映されない可能性があるので、よくわからない方はとりあえず同じBoxを使用してください。 Vagrant Boxをinitする 先ほどのコマンドを使用して、Boxのinitを行います。 コマンドプロンプトから実行してもいいのですが、Visual Studio Code は、エディタ内でコマンド操作を行う事ができるのでVisual Studio Codeから実行しましょう。 「表示」→「ターミナル」もしくは ショートカットキー Ctrl + @ でターミナルを開きます。 Visual Studio Codeで開いてるフォルダが自動的にカレントディレクトリになります。 ためしにVagrantのバージョンを表示してみましょう。 powershell vagrant -v Vagrantのバージョンが正しく表示されました。 では、先ほど確認したVagrant Boxのコマンドを実行します。 ※少し時間がかかります。 powershell vagrant init bento/centos-7.5 コマンド実行後、「C:\work\test」フォルダに「Vagrantfile」が作成されました。 作成されたVagrantfileを編集する Visual Studio Code 上で、先ほど作成したVagrantfileを開きます。 中身を以下に書き換えます。 Vagrantfile Vagrant.configure("2") do |config| config.vm.box = "bento/centos-7.5" config.vm.network "private_network", ip: "192.168.33.10" Encoding.default_external = 'UTF-8' config.vm.provision :shell, path: "provision.sh" end 「config.vm.box」は先ほどinitしたVagrantのBox名が指定されています。 「config.vm.network」の「ip:」は任意のIPアドレスを指定します。 ここを設定することによって、ローカルのホストOSから仮想のゲストOSにhttp接続できるようになります。 「config.vm.provision」はこのあと解説する、provision.shファイルを指定します。 provision.shを作成する provisionとは、Vagrantの初回起動時に、自動で実行してくれるスクリプトです。 provisionに処理を記載しておくことで、初回の環境構築を自動化する事ができます。 これがVagrantを使用するメリットのひとつです。 「Vagrantfile」があるフォルダと同じ階層に「provision.sh」を作成します。 今回だと「C:\work\test\provision.sh」です。 作成した「provision.sh」を開き、PHP 7.1 の開発環境を構築するための以下のコードを貼り付けます。 provision.sh # Apacheのインストール sudo yum -y install httpd # Firewallsの無効 sudo systemctl stop firewalld # EPELのリポジトリ追加 sudo yum -y install epel-release # Remiのリポジトリ追加 sudo yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm # PHPのインストール sudo yum -y install --enablerepo=remi,remi-php71 php php-cli php-common php-devel php-mbstring php-pdo php-gd php-xml php-mcrypts php-pecl-xdebug # httpd.confの設定書き換え sudo cp -f /vagrant/conf/httpd.conf /etc/httpd/conf/httpd.conf # シンボリックリンクの作成 cd /var/www sudo rm -r html sudo ln -s /vagrant/html /var/www/html # 自動起動設定 sudo systemctl enable httpd.service # Apacheの起動 sudo systemctl start httpd # 完了 echo "provisioning success" 共有フォルダを作成する vagrantfileがあるフォルダに「html」フォルダを作成します。 今回だと「C:\work\test\html」です。 「provision.sh」でシンボリックリンクの作成の処理を記載しているので、ローカルのホストOSの「C:\work\test\html」フォルダと、仮想のゲストOSの「/var/www/html」フォルダが共有されます。 フォルダ共有しておくと、ローカルのホストOSで編集したhtmlが、仮想のゲストOSでも反映されるのでとても便利です。 Apache設定ファイルを作成する Apacheの設定ファイルの「httpd.conf」を作成します。 Vagrantfileがあるフォルダに「conf」フォルダを作成し、その中に「httpd.conf」ファイルを作成します。 今回だと「C:\work\test\conf\httpd.conf」です。 「httpd.conf」ファイルを開き、以下のコードを貼り付けます。 httpd.conf ServerRoot "/etc/httpd" Listen 80 Include conf.modules.d/*.conf User apache Group apache ServerAdmin root@localhost <Directory /> AllowOverride none Require all denied </Directory> DocumentRoot "/var/www/html" <VirtualHost *:80> DocumentRoot /var/www/html/test </VirtualHost> <Directory "/var/www"> AllowOverride None Require all granted </Directory> <Directory "/var/www/html"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> <IfModule dir_module> DirectoryIndex index.html </IfModule> <Files ".ht*"> Require all denied </Files> ErrorLog "logs/error_log" LogLevel warn <IfModule log_config_module> LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common <IfModule logio_module> LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio </IfModule> CustomLog "logs/access_log" combined </IfModule> <IfModule alias_module> ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" </IfModule> <Directory "/var/www/cgi-bin"> AllowOverride None Options None Require all granted </Directory> <IfModule mime_module> TypesConfig /etc/mime.types AddType application/x-compress .Z AddType application/x-gzip .gz .tgz AddType application/x-httpd-php .php AddType application/x-httpd-php-source .phps AddType text/html .shtml AddOutputFilter INCLUDES .shtml </IfModule> AddDefaultCharset UTF-8 <IfModule mime_magic_module> MIMEMagicFile conf/magic </IfModule> EnableSendfile off IncludeOptional conf.d/*.conf 「VirtualHost」には、バーチャルホストに対してのみ適用されるディレクティブ群を記載します。 今回は、「/var/www/html/test」をドキュメントルートとします。 「provision.sh」で、「httpd.conf」をローカルのホストOSから仮想のゲストOSへコピーするスクリプトを記述しているので、仮想マシン起動時にApacheの設定が仮想環境へコピーされます。 仮想マシンを起動する Visual Studio Codeのターミナルで以下のコマンドを実行します。 powershell vagrant up Vagrantfileが存在するディレクトリで実行してください。 今回だと「C:\work\test」です。 vagrant up コマンドを実行すると、デフォルトのプロバイダであるVirtualBoxが起動します。 「Vagrantfile」に記載したBoxを追加し、仮想環境を自動で構築してくれます。 「このアプリ(VirtualBox)がデバイスに変更を加えることを許可しますか?」というダイアログが出た場合は、「はい」を選択してください。 初回なので、起動に時間がかかります。 仮想マシンが起動されたか確認するには、「vagrant status」コマントを実行してください。 powershell vagrant status 仮想マシンが起動されていれば、「running (virtualbox)」と表示されます。 仮想マシンにログインする 仮想マシンが起動出来たら、ログインしましょう。 ターミナルで以下のコマンドを実行してください。 powershell vagrant ssh 仮想マシンに接続されたら、Apacheが起動しているか確認しましょう。 powershell service httpd status Apacheが起動していれば「Active: active (running)」と表示されます。 「provision.sh」で、仮想マシン起動時に自動的にApacheを起動させる設定にして環境構築しているので、今後もApacheは自動で起動してくれるはずです。 もし起動していなければ、以下のコマンドで起動させることもできます。 powershell sudo systemctl start httpd Webページを表示させる これで環境が整いました。 いよいよWebページを表示させてみましょう。 phpファイルを作成する。 ドキュメントルートにあたるフォルダに「index.php」ファイルを作成します。 仮想マシンのドキュメントルートは「httpd.conf」で指定した「/var/www/html/test」です。 「html」フォルダはローカルのホストOSと共有されているので、ローカルの「html」フォルダに「test」フォルダを作成し、その中に「index.php」ファイルを作成します。 今回だと「C:\work\test\html\test\index.php」です。 「index.php」ファイルを開き、以下のコードを貼り付けます。 index.php <!DOCTYPE HTML> <html> <body> </div> <?php print "PHPのバージョンは、" . phpversion(); ?> </div> </body> </html> ローカルのホストOSからウェブブラウザを開き、「Vagrantfile」に記載したIPアドレスにアクセスします。 今回は「192.168.33.10」です。 無事に表示されました。 ログアウト・シャットダウン方法 仮想マシンからログアウトするには「exit」コマンドを使用します。 powershell exit 仮想マシンをシャットダウンするには以下のコマンドを実行します。 powershell vagrant halt コマンドについて Vagrantのコマンド例 ※Vagrantfileが存在するディレクトリで実行すること コマンド 内容 vagrant up 仮想マシンを起動する vagrant halt 仮想マシンをシャットダウンする vagrant reload 仮想マシンを再起動する vagrant destroy 仮想マシンを廃棄する vagrant status 仮想マシンの状態を確認する vagrant ssh 仮想マシンにSSH接続する Vagrant Boxのコマンド例 コマンド 内容 vagrant box list Boxの一覧を表示する vagrant box remove [Box名] Boxを削除する Apacheのコマンド例 コマンド 内容 service httpd status Apacheのサービスの状態を確認する httpd -v Apacheのバージョンを調べる sudo service httpd start Apacheを起動する sudo service httpd stop Apacheを停止する sudo service httpd restart Apacheを再起動する おわりに 開発環境の構築はたまにしかやらないので、久しぶりにやると、前どうやったんやっけ。。。?と困る事が多く、一旦手順をまとめてみました。 Apacheの設定などがあまり理解出来ていないので、ちゃんと勉強しないといけないですね。 しかしVagrantはいいですね。 PCの環境も汚れないし、一度環境構築すれば、次回からは Visual Studio Code を起動 ターミナルを表示 「vagrant up」コマンドを入力 の3Stepだけで、開発環境が整うのでめちゃくちゃ便利です。 参考サイト Vagrant + VirtualBoxでWindows上に開発環境をサクッと構築する 【Linux環境構築】VagrantとVirtualBoxとは?使い方を初心者向けに解説!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】<?= ?>の意味:大なり クエスチョン(はてな)イコール

Laravelのビューを見ていて<?= ?>という記述にでくわした。何をしているか解読するまでに時間がかかったのでそのメモ。 <?php ?>, <? ?>, '<?= ?>'の違いについても。 結論 先に結論から。それぞれhtmlファイルの中でPHPを記述するためのタグ。 <?php ?>や<?php echo ?>の省略形。 コード 共通 概要 <?php ?> PHPを記述する <? ?> <?php ?> XMLの記述と被るため使わない <?= ?> <?php echo ?> 記述したPHPを文字列として出力 (echo)する ▼Laravelのブレード内で使う場合 Laravelのブレード(.blade.php)を使っているなら以下は同じになる。(例として$variableという変数を文字列として表示する場合) <?= $variable ?> ↑↓同じ @php echo $variable @endphp <?= ?>の意味 <?php echo ?>の省略形。echoの後ろに変数を記述すると、その中身は出力される。 ▼使い方の例 変数$variableを文字列として表示する。 <?= $variable ?> 例2 cssをstyleタグの中に直接記述する cssをlinkタグではなく、styleタグの中に直接記述することで、レンダリングブロックを回避しページの読み込み速度を上げる。 <style type="text/css"> <?= file_get_contents(public_path('css/app.css')); ?> </style> ・file_get_contents(ファイルパス or URL) 指定したファイルやURLの内容を丸ごととってくる。PHPの関数。 ・public_path(public配下のファイルパス) public_path()はpublicディレクトリの完全なパスを返す。引数に配下のパスを入れると、publicディレクトリのパスに引数を追加した値を返す。Laravelのヘルパ。 <?php ?> と <? ?> <?php ?>の省略形として<? ?>と書くこともできるが、XMLの記述と被るため基本使わない。 参考リンク
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DirCaster をmp4対応にする。

podcastで mp4形式を 使いたくなったので Dircaster を 改修した ときのメモ dircaster.php switch (strrchr(strtolower($file), ".")) { --略-- case ".m4a"; case ".mp4"; $tit = @$ThisFileInfo['quicktime']['comments']['title'][0]; // artist from any/all available tag formats $alb = @$ThisFileInfo['quicktime']['comments']['album'][0]; // artist from any/all available tag formats $art = @$ThisFileInfo['quicktime']['comments']['artist'][0]; // artist from any/all available tag formats $com = @$ThisFileInfo['quicktime']['comments']['comment'][0]; // artist from any/all available tag formats $cmp = @$ThisFileInfo['quicktime']['comments']['writer'][0]; // artist from any/all available tag formats と .m4a の case 文のつぎの行に .mp4 を 追加する。 config_inc.php // Allowed File Types (file extensions) in Feed URL, make sure your type is listed $sftypes = "(.mp3 .aac .m4a .mp4 .asf .wma .wav .avi .mov .m4b .m4v)"; 設定ファイルの 対象ファイルに .mp4 を 追加する。 これだけです。 RSSフィードに アクセスして ファイルのURLが 表示されていることを 確認したあと posdcastツールで 読み込んで再生できることを確認。 mp4 が 配信できるようになりました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IntelephenseでPHAR版のPHPUnitのコード補完を効かせる

私はPHPUnitを依存関係に組み込むのが嫌なので、PHPUnitのインストールはComposerを使わずにPHIVEを使ってPHARをダウンロードすることで行っています。 PHIVEの基本的なことについては下記の記事を読むとわかると思います。 PHAR版のPHPUnitの困ること PHAR版のPHPUnitを使うと依存関係を汚さなくて済むのですが、困ることもあります。 それはテストコードを書く際にIntelephenseでassertEquals等のメソッドがエラーになったり、コード補完が効かなかったりすることです。 これらはIntelephenseがPHARファイルを読み込んでくれないことに起因します。 assertEqualsメソッドが存在しないというエラーが出ます。 コード補完も効きません。 解決方法 解決方法は至極単純で、PHARを展開して中に含まれるPHPファイルを取り出すことです。 PHARを展開してプロジェクトディレクトリ配下のどこかに置けば、それをIntelephenseが読み込んでくれるようになり、エラーが消えてコード補完も効くようになります。 下記のようなコードを書いて実行すればPHARを展開できます。 <?php $phar = new Phar('.phive/phars/phpunit-9.5.4.phar'); $phar->extractTo('tools-src'); 上記のコードではPHPUnitのPHARをtools-srcディレクトリに展開しています。 展開後にテストコードを開くとassertEqualsメソッドのエラーが消えました。 コード補完も効くようになりました。 おまけ PHARを展開するためのコマンドを作って公開しています。 特定のPHARを展開するだけでなく、ディレクトリに含まれるPHARを一括で展開したり、PHIVEのphars.xmlに記載されているPHARを一括で展開したりできます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む