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

Laravel5.6以降のLog設定の小ネタ

config/log.phpでログを設定するようになってからの設定方法についての小ネタ。
ドキュメントに明示されておらず、StackOverflow等でもなかなか出てこないので書いておく。

monolog driver以外でも、Formatterはconfig/log.phpで指定できる

https://laravel.com/docs/6.x/logging#customizing-monolog-for-channels

Monolog Formatters
When using the monolog driver, the Monolog LineFormatter will be used as the default formatter. However, you may customize the type of formatter passed to the handler using the formatter and formatter_with configuration options:

'browser' => [
    'driver' => 'monolog', // <= simpleドライバなどでもformatter指定できる
    'handler' => Monolog\Handler\BrowserConsoleHandler::class,
    'formatter' => Monolog\Formatter\HtmlFormatter::class,
    'formatter_with' => [
        'dateFormat' => 'Y-m-d',
    ],
],
  • ドキュメントには monolog ドライバー用のオプションのように書かれているが、 simpledaily のdriverであっても同様に、formatterパラメータが有効
    • 同様にformatter_withも有効

tap()時、getHandlers()で全ハンドラを回さなくても直接$logger->pushProcessor()できる

ドキュメントの tap() のサンプルが以下のように書かれているため、プロセッサの設定でも同様のループを書いていることが多い

// tapの処理サンプル
public function __invoke($logger)
{
    foreach ($logger->getHandlers() as $handler) {
        $handler->setFormatter(...);
    }
}
public function __invoke($logger)
{
    foreach ($logger->getHandlers() as $handler) {
        // ならこうやろ!
        $handler->pushProcessor(...);
    }
}

※このサンプルに引っ張られて上記Formatterの設定を tap() でやってしまう疑惑

  • __invoke($logger) に渡される実体は Monolog\Logger
  • Loggerのスタック全体に対して適用するProcessorを pushProcessor() で突っ込める ⇒ソース

            public function __invoke($logger)
            {
                // 全部に適用したいならこれで十分
                $logger->pushProcessor(...);
            }
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby、PHP、Java、JSでの書き方の違い

はじめに

「Rubyでプログラミングの基礎を学んだから、次はjsやってみようかな!」

「書き方ごちゃごちゃになって、何が何だかよくわかんねー!!」

こんな人もいるのでは?

僕自身も以前、詰め込みすぎでパンパンになりましたので、書き方の違いをわかりやすくまとめてみました。
一つ一つ覚える必要はありませんので、この記事を、ストックしていただければと思います。
オブジェクト指向の理解も多少深まると思いますので、最後までご覧ください!

文字出力

基本となる文字の出力。言語によって処理のされ方が違うので難しいところですが、基本なのでしっかり押さえましょう。Javaはやっぱり記述が長いですねw

  #Ruby
  puts "こんにちは"
  #PHP
  echo "こんにちは";
  //Java
  System.out.println("こんにちは");
  //JavaScript
  console.log("こんにちは");

変数代入

プログラミングの超基本、変数代入です。

  #Ruby
  name = "Tom"
  #PHP
  $name = "Tom";
  //Java(String、intなどの型を指定する)
  String name = "Tom";
  //JavaScript
  let name = "Tom";

変数展開、文字列+変数

これもよく使いますね。全部似てますが、違いがあります。※書き方はあくまで一例です

  #Ruby
  "私の名前は#{name}です。"
  #PHP
  "私の名前は{$name}です。"
  //Java
  "私の名前は"+ name + "です。"
  //JavaScript(''ではなく``(バッククオーテーション)で囲む)
  `私の名前は${name}です。`

if文

処理の代表と言えばif文でしょう。elsifのところの違いに注意です。

  #Ruby
  if age >= 20
    #処理
  elsif age >= 10
    #処理
  else
    #処理
  end
  #PHP
  if (age>= 20){
    #処理
  }elseif (age >= 10){
    #処理
  }else{
    #処理
  }
  //Java & JavaScript
  if (age>= 20){
    //処理
  }else if (age >= 10){
    //処理
  }else{
    //処理
  }

配列と取り出し方

配列の取り出しもよく使いますね、1つづつ取り出す方法も言語によっていろんなのがあります。

  #Ruby
  names = ["Tom","Kenta","John"]
  names[0]
  #PHP
  $names = array("Tom","Kenta","John");
  $names[0];
  //Java
  String names[] = {"Tom","Kenta","John"};
  names[0];
  //JavaScript
  const names = ["Tom","Kenta","John"];
  names[0];

ハッシュ、連想配列、オブジェクトと取り出し方

言語によって呼び方が違うので、検索する際には注意してください。

  #Ruby(ハッシュ)
  user = {name: "Tom",age: 20}
  user[:name]
  #PHP(連想配列)
  $user = array("name" => "Tom","age" => 20)
  $user["name"]
  //JavaScript(オブジェクト)
  const user = {name: "Tom",age: 20};
  user.name

通常のメソッド、関数

ここからが重要なところです。今回は2つの値を合計するaddメソッド(関数)を作りました。
戻り値も重要なので、しっかり押さえましょう。

  #Ruby
  def add(a, b)
    return a + b
  end
  sum = add(5, 2)
  #PHP
  function add($a, $b){
    return $a + $b;
  }
  $sum = add(5, 2);
  //Java
  public static int add(int a, int b){
  //staticの後のintは戻り値の型を指定、戻り値がないメソッドの場合はvoidを使用
    return a + b; 
  }
  int sum = add(5, 2);
  //JavaScript
  const add = function(a, b){
    return a + b;
  };
  let sum = add(5,2);

  //または
  const add = (a, b) => {
    return a + b;
  };
  let sum = add(5,2);

  //または
  function add (a, b){
    return a + b;
  }
  let sum = add(5,2);

jsはバージョンによって推奨されている記述が違います。

クラスとインスタンス作成

さあ、待ちに待ったオブジェクト指向の始まりです!
Menuクラスを作って、そのクラスをもとに、インスタンスを作成し変数menu1に代入しています。

  #Ruby
  class Menu
    ##処理
  end
  menu1 = Menu.new
  #PHP
  class Menu{
    ##処理
  }
  $menu1 = new Menu();
  //Java
  class Menu{
    //処理
  }
  Menu menu1 = new Menu();
  //JavaScript
  class Menu{
    //処理
  }
  const menu1 = new Menu();

インスタンス変数、インスタンスフィールド、プロパティの定義

メニューには名前や値段などの"情報"が含まれます。それをクラス内で事前に宣言しておきます。

  #Ruby
  attr_accessor :name
  attr_accessor :price
  #PHP
  private $name;
  private $price;
  //Java
  private String name;
  private int price;
  //JavaScript
  //事前定義は不要?

初期メソッドでのインスタンス変数、プロパティへの代入

さあ、さらに訳わからないところにやってきました!
初期メソッドとはnewされた時(一番最初)に呼ばれるメソッドになります。
今回はnewの引数に指定された値が初期メソッド内で、インスタンスの情報として変数に入ります。

  #Ruby
  def initialize(name, price)
    self.name = name
    self.price = price
  end
  menu1 = Menu.new("ハンバーガー",300)
  #PHP
  public function __construct($name,$price){
    this->name = $name;
    this->price = $price;
  }
  $menu1 = new Menu("ハンバーガー",300);
  //Java
  //クラス内でクラスと同名のメソッドを定義する
  Menu(String name, int price){
    this.name = name;
    this.price = price;
  }
  Menu menu1 = new Menu("ハンバーガー",300)
  //JavaScript
  constructor (name, price){
    this.name = name;
    this.price = price;
  }
  const menu1 = new Menu("ハンバーガー",300)

インスタンスメソッドと呼び出し

さて最後になります。インスタンスは"情報"の他に"処理"を持っています。
今回はその処理の定義方法と呼び出し方です。
変数menu1にはMenuクラスから作られたインスタンスが代入されているので、
出力は"こちらのハンバーガーは300円です"となります。

  #Ruby
  def show
    puts "こちらの#{self.name}#{self.price}円です"
  end
  menu1.show
  #PHP
  public function show(){
    echo "こちらの{$this->name}{$this->price}円です";
  }
  $menu1->show();
  //Java
  public void show(){
    System.out.println("こちらの"+this.name+"は"+this.price+"円です");
  }
  menu1.show();
  //JavaScript
  show(){
    console.log(`こちらの${this.name}${this.price}円です`);
  }
  menu1.show();

終わりに

最後までご覧いただきありがとうございました。
抜けや間違いがあるかもしれませんが大目に見てください!!

この世の中では浅く広く学ぶのはあまり良くないとされていますが、知識を深めるために別言語に挑戦してみるのもいいと私は思います。

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

Laravel Dusk テストコード作成時の困った場合の対処法

Laravel dusk でブラウザテストを作成していて困った部分の対処法のメモです。
間違っている箇所があればご指摘いただけましたら幸いです。

dusk失敗の原因が知りたい

app\tests\Browser\screenshots配下に失敗時の画面スクリーンショットが作成されます。

The MAC is invalid.

暗号化キーを再生成する → php artisan key:generate
※暗号化したパスワードが複号できなくなるので取り扱い注意
[引用]
https://error-search.com/error-post/detail/144/The%2BMAC%2Bis%2Binvalid.

Operation timed out after 30001 milliseconds with 0 out of -1 bytes received

jsの読み込みがが遅い場合、テストの速度に画面が追い付いていない場合に出現するエラーです。
waitFor waitForText なりを入れてから検証すること。

要素の表示をwaitで待つ

$browser->waitForText('検索', 30);
$browser->waitFor("#search", 30);

jsで最前面に表示される画面の要素のclickができないとき

素のjsでクリックする(サービスプロバイダにマクロを登録する 下記 clickToElement 参照)

//クリックする
$browser->clickToElement(".search_btn");

画面内に表示されていない要素がクリックできないとき

素のjsで要素にスクロールする (サービスプロバイダにマクロを登録する 下記 scrollToElement 参照)

[参考]
https://readouble.com/laravel/5.7/ja/dusk.html (ブラウザマクロ)
https://readouble.com/laravel/5.3/ja/providers.html (サービスプロバイダ)
https://github.com/laravel/dusk/issues/203 (マクロ登録例)

<?php
namespace App\Providers;

use Laravel\Dusk\Browser;
use Illuminate\Support\ServiceProvider;

class DuskServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        Browser::macro('scrollToElement', function ($element = null) {
            $this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");

            return $this;
        });

        Browser::macro('clickToElement', function ($element = null) {
            $this->script("document.querySelector('$element').click();");

            return $this;
        });

        Browser::macro('switchFrame', function ($frame = null) {
            if ($frame) {
                $this->driver->switchTo()->defaultContent()->switchTo()->frame($frame);
            } else {
                // Main frame
                $this->driver->switchTo()->defaultContent();
            }
            return $this;
        });
    }
}

testの中断(Ctrl + c)でDB接続先がずれた?

.env / .env.dusk.local の DB_HOST= を確認する。

chromeの設定ファイル (UAを変えたい 画面サイズを変更したいなどはここで)

DuskTestCase.php

$ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.91 Mobile/15E148 Safari/605.1';
        $options->setExperimentalOption('mobileEmulation', ['userAgent' => $ua]);

head部分のテスト

duskはcssセレクターで検証しようとすると先頭に'body'がつくため、bodyタグより上の要素の検証をしたい場合はこの書き方で

 $browser->assertSourceHas("<meta name=\"description\" content=\"Qiitaは情報満載!\">");

xpathを使って要素の値を取り出すことも可能 (xpathも使えます)

use Laravel\Dusk\Browser;
use Facebook\WebDriver\WebDriverBy; //xpath用
略
$browser->driver->findElement(WebDriverBy::xpath("//link[@rel='canonical']"))->getAttribute('href')

Rspec の before after のようなものを実装したい

[参考]
https://cpoint-lab.co.jp/article/201812/7155/

public function setUp() :void
{
    parent::setUp();
    // テストデーターの準備などを行う
}

PHPUnitのアサーションも使えます

$this->assertEquals($element_count, 50);

セッションの破棄

  $browser->driver->manage()->deleteAllCookies();

function日本語化(@testつける)

/**
 * @test
 */
public function ステータステスト()
{
    $res = $this->get("url");
    $res->assertStatus(200);
}

テストをグループ化して実行 (@group アノテーションでグループ化)

php artisan dusk tests/Browser/ --group samplegroup

/**
 * @group samplegroup
 */
public function sampleTest()
{
   //処理

テストをファイル単位で実行

php artisan dusk tests/Browser/SampleTest.php

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

phpのスーパーグローバル変数の定義variables_orderについて

variables_orderとは

php.iniには以下の定義があります。

variables_order = "EGPCS"

それぞれスーパーグローバル変数の作成をする定義をします。
それぞれ頭文字で以下を表わします。

E:Environment (環境変数)
G:Get
P:Post
C:Cookie (クッキー)
S:Server

Eは指定しないほうがいいのか?

phpのバージョンによってはデフォルト値が変わってくるようです。
7.3に上げたら"GPCS"となりました。

; This directive determines which super global arrays are registered when PHP
; starts up. G,P,C,E & S are abbreviations for the following respective super
; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty
; paid for the registration of these arrays and because ENV is not as commonly
; used as the others, ENV is not recommended on productions servers. You
; can still get access to the environment variables through getenv() should you
; need to.
; Default Value: "EGPCS"
; Development Value: "GPCS"
; Production Value: "GPCS";
; http://php.net/variables-order

コメントにもあるとおりEは推奨しないとのことです。
パフォーマンスにも影響するようです。

CGI および FastCGI SAPI の両方で、 $_SERVER にも環境変数の値が格納されます。 つまり、S を指定すると、 ES と指定したのと同じ意味になります。 これは、E が他のどこかで指定されていたとしても同じです。

ちなみにこの一文のようにphp-fpmを使用しているとENVとSERVERには同様の値が入っていました。
なのでEは指定する必要がなおさらなさそうですね。

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

【laravel】マイグレーション、やり直しコマンドいろいろ

テーブルの修正、再構築のコマンドについて簡単にメモします。

マイグレーションはそのDBのmigrationsテーブルで管理されます。
migrationsテーブルにはbatchというカラムがあり、値の順にmigrateされたことを表します。下のDBではcreate_photos_tableファイルが直近で実行されたということになります。
スクリーンショット 2020-02-05 11.51.43.png

status

マイグレーションの状態を確認します。

php artisan migrate:status

+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 1     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 1     |
| Yes  | 2020_02_05_015307_create_albums_table          | 2     |
| Yes  | 2020_02_05_020352_create_photos_table          | 3     |
+------+------------------------------------------------+-------+

このDBでは1,2,3の順でマイグレーションが実行されたこと表しています。

rollback

ロールバック(直前に行った一連のマイグレーションをなかったことにする)
・down()メソッドに書かれた処理が実行されます。
・先ほどのDBではbatchが3のマイグレーションがロールバックされ、状態は「No」と表示される

$ php artisan migrate:rollback

ロールバックが実行されるとRanのところが「No」と表示されます。

+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 1     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 1     |
| Yes  | 2020_02_05_015307_create_albums_table          | 2     |
| No   | 2020_02_05_020352_create_photos_table          |       |
+------+------------------------------------------------+-------+

・--stepのオプションで[数値]回のロールバックを行います。
batchの値が3の場合、php artisan migrate:rollback --step=2をするとbatchが1の状態まで戻ります。

$ php artisan migrate:rollback --step=[数値]

reset

すべてのマイグレーションをロールバックします。

$ php artisan migrate:reset
$ php artisan migrate:reset
Rolling back: 2020_02_05_015307_create_albums_table
Rolled back:  2020_02_05_015307_create_albums_table 
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back:  2019_08_19_000000_create_failed_jobs_table 
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table 
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table 

$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| No   | 2014_10_12_000000_create_users_table           |       |
| No   | 2014_10_12_100000_create_password_resets_table |       |
| No   | 2019_08_19_000000_create_failed_jobs_table     |       |
| No   | 2020_02_05_015307_create_albums_table          |       |
| No   | 2020_02_05_020352_create_photos_table          |       |
+------+------------------------------------------------+-------+

すべてのマイグレーションの状態が「No」となります。

refresh

すべてのマイグレーションをロールバックしてから再びマイグレーションします。

$ php artisan migrate:refresh
$ php artisan migrate:refresh

Rolling back: 2020_02_05_020352_create_photos_table
Rolled back:  2020_02_05_020352_create_photos_table (0.02 seconds)
Rolling back: 2020_02_05_015307_create_albums_table
Rolled back:  2020_02_05_015307_create_albums_table (0.02 seconds)
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back:  2019_08_19_000000_create_failed_jobs_table (0.02 seconds)
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table (0.02 seconds)
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table (0.02 seconds)
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.06 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.04 seconds)
Migrating: 2020_02_05_015307_create_albums_table
Migrated:  2020_02_05_015307_create_albums_table (0.04 seconds)
Migrating: 2020_02_05_020352_create_photos_table
Migrated:  2020_02_05_020352_create_photos_table (0.04 seconds)

fresh

すべてのテーブルをドロップ(削除)してから再びマイグレーションします。

$ php artisan migrate:fresh

Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.06 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.04 seconds)
Migrating: 2020_02_05_015307_create_albums_table
Migrated:  2020_02_05_015307_create_albums_table (0.04 seconds)
Migrating: 2020_02_05_020352_create_photos_table
Migrated:  2020_02_05_020352_create_photos_table (0.04 seconds)

refreshと異なるのはロールバックが行われないこと。つまりdown()メソッドが実行されずにDBの再構築が行われる点。
したがって複数DBを持つプロジェクトではfreshを行うとエラーが出てしまいます。なぜなら一方のDBだけが削除されてしまうためです。

まとめ

status マイグレーションの状態確認
rollback 直前のマイグレーションをロールバック
reset すべてのマイグレーションをロールバック
refresh すべてのマイグレーションをロールバックしmigrateを実行。
fresh すべてのテーブルを削除しmigrateを実行。

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

Laravel Requestが全部string型なのを何とかする

はじめに

弊社は

<?php
declare(strict_types=1);

を指定し、強い型付け制約をしています。

その環境下で開発していたControllerでこんなエラーが。

PHP Fatal error:  Uncaught TypeError: Argument 1 passed to show() must be of the type integer, string given,

// 訳:おい、show()メソッドの引数にstring渡してるけど、integerしか受け付けねーから!

そのコードがこれ。

// Controller
public function index(Request $request)
{
    return $this->service->show($request->get('id'));
}

// Service
public function show(int $id): array
{
    return $this->model->detail($id)->toArray();
}

???
$request->idはintでしょ?

実験コード

public function index(Request $request)
{
    var_dump($request-all());
}

GET

// idが数字、is_deletedがbooleanを指定しているつもり
http://xxxx.com/show?id=1&is_deleted=true

結果

  'id' => string '1' (length=1)
  'is_deleted' => string 'true' (length=4)

POST

<form method="POST" action="http://xxxx.com/show">
    <input type="text" name="id">
    <input type="text" name="id_deleted">
</form>

結果

  'id' => string '1' (length=1)
  'is_deleted' => string 'true' (length=4)

悲報

全部stringだった \(^o^)/

じゃあcastすればいいじゃん

いやーそうなんですけど、1個や2個のパラメータならともかく、ちょっと多くなると面倒くさいし見づらくなりません?

public function index(Request $request)
{
    return $this
        ->service
        ->show(
            (int)$request->get('id'),
            (bool)$request->get('is_deleted'),
            (float)$request->get('lat'),
            (float)$request->get('lon')
        );
}
// なんかダサい

よしなにキャストしてくれればいいのになー

コントローラに着弾した時点でRequestの値が適切にキャストされていて、安全に使えないないか、と考えていました。
そのときに気づいたのは、
「あれ、コントローラに着弾した時点で安全な値が担保されているって、LaravelのFromRequestValidationと似てるな」
ということ。

なるほど、FormRequestで値のクリーニングもしちゃえばいいのか。

やってみた

こんな感じのFormRequest拡張を作って・・・

<?php
declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest as BaseFromRequest;

class FormRequest extends BaseFromRequest
{
    /**
     * @var array キャストルール
     */
    protected $casts = [];

    /**
     * 整形したパラメータを返却する
     * @param string $key
     * @return bool|int|array|string|mixed
     */
    public function shaped(string $key)
    {
        $target = $this->trim($this->get($key, null));
        if (empty($this->casts)) {
            return $target;
        }
        if (!isset($this->casts[$key])) {
            return $target;
        }
        return $this->cast($this->casts[$key], $target);
    }

    /**
     * パラメータ前後の空白等を削除
     * @param mixed $target
     * @return array|string|null
     */
    private function trim($target)
    {
        if (is_null($target)) {
            return null;
        }
        if (!is_array($target)) {
            return trim($target);
        }
        $trimmed = [];
        foreach ($target as $value) {
            $trimmed[] = trim($value);
        }
        return $trimmed;
    }

    /**
     * パターンに応じてキャストする
     * @param string $castPattern
     * @param mixed $target
     * @return bool|int|array|string|mixed
     */
    private function cast(string $castPattern, $target)
    {
        switch ($castPattern) {
            case 'integer':
                return (int)$target;
                break;

            case 'bool':
                if ($target === 'true') {
                    return true;
                }
                if ($target === 'false') {
                    return false;
                }
                throw new Exception();
                break;

            case 'json_decode':
                return json_decode($target, true);
                break;

            case 'string':
            default:
                return $target;
        }
    }
}

バリデーションを書くFormRequestクラスは↑のクラスをextendするように・・・

<?php
declare(strict_types=1);

namespace App\Http\Requests;

class CustomerRequest extends FormRequest
{
    /**
     * @var array キャストルール
     */
    protected $casts = [
        'id' => 'integer',
        'is_deleted' => 'bool',
    ];

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'id' => 'integer',
            'is_deleted' => 'bool',
        ];
    }
}

それをコントローラでインジェクションしたならば・・・

public function index(CustomerRequest $request)
{
    var_dump($request->shaped('id'));
    var_dump($request->shaped('is_deleted'));
}
ExampleController.php:34:int 1
ExampleController.php:35:boolean true

これでクールなコントローラが書けそうです。

注釈

  • 題名にはLaravelと記載しましたが、そもそもPHPへ送られてくるGETリクエストや、POSTリクエストのContent-Typeに”application/x-www-form-urlencoded”、”multipart/form-data”が指定されていた場合全部string型(かarray)です。
  • 抜本的に解決するためには、”application/json”でリクエストするとLaravelはちゃんと型を解決します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker環境にてPHPのデバッグができるかどうか、やってみた

はじめに

・今の職場にてPHPの開発をしているだが、デバッグができなくて困っている。苦肉の策でログを出しながら確認しているが、なんとかしたいと思い。
最近かじったDocker環境にてPHPのデバッグができる様なので、試しにやってみた。

環境

・使用パソコンスペック
PC: Razer Brade pro 2019
OS: Ubuntu 18.04 LTS
Docker: version 19.03.5
Docker Compose: version 1.17.1
PHP: php:7.2.7-apache (Apacheと連携されているコンテナ)
Xdebug: 2.7.0
Visual Studio Code: 1.41.1

Dockerfile
FROM php:7.2.7-apache

RUN apt-get update && \
    docker-php-ext-install mysqli && \
    pecl install xdebug
docker-compose.yml
version: '3'

services:
  php:
    build: ./php
    ports:
      - '80:80'
    volumes:
      - ./php/html:/var/www/html
      - ./php/conf/php.ini:/usr/local/etc/php/php.ini
      - ./php/log/xdebug:/var/log/xdebug
php.ini
[Date]
date.timezone = "Asia/Tokyo"

[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

[xdebug]
; xdebugのインストール先を指定(Dockerコンテナ内)
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20170718/xdebug.so
xdebug.remote_enable=1
xdebug.remote_autostart=1
; デバッグで使用するポートを指定(デフォルト値)
xdebug.remote_port=9222
; Dockerコンテナ内部から見たホストを指定
xdebug.remote_host=host.docker.internal
; ログ出力先
xdebug.remote_log=/var/log/xdebug/xdebug.log
xdebug.remote_connect_back=1
launch.json
{
  "version": "0.1.0",
  "configurations": [
    {
      "name": "Listen for XDebug",
      "type": "php",
      "request": "launch",
      "port": 9222,
      "pathMappings": {
        // Dockerコンテナのdocument root : 開発環境のdocument root
        "/var/www/html":"${workspaceFolder}/php/html" 
      }
    }
  ]
}
index.php
<?php

echo 'Hello World<br>';

はまった点

・Dockerの立ち上げから、HTTPへのアクセスまではすんなりいったが、ブレイクポイントで止まらなかった。結果、launch.jsonのポートの設定を自分の環境で使用しているものに変更したら動きました。
・xdebugのインストール先を指定(Dockerコンテナ内)をphp.iniファイルに記入するのが抜けていたため動かなかった。※環境によってパスが変わるようであり、Dockerを立ち上げたときにコマンド上でインストールされたパスが確認できる。

参考にさせていただいたリンク

・Docker-composeのコマンド
https://qiita.com/okyk/items/a374ddb3f853d1688820
・構築方法
https://qiita.com/MasanoriIwakura/items/a310c75e6c5b347adf37

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

Docker環境にて、PHPのデバッグができるかどうか試しにやってみた

はじめに

・今の職場にてPHPの開発をしているだが、デバッグができなくて困っている。苦肉の策でログを出しながら確認しているが、なんとかしたいと思い。
最近かじったDocker環境にてPHPのデバッグができる様なので、試しにやってみた。

使用ツール

項目 バージョン
PC Razer Brade Pro 2019
OS Ubuntu 18.04 LTS
Docker 19.03.5
Docker-Compose 1.17.1
PHP php:7.2.7-apache (連携されているコンテナ)
Xdebug 2.7.0
Visual Studio Code 1.41.1
Dockerfile
FROM php:7.2.7-apache

RUN apt-get update && \
    docker-php-ext-install mysqli && \
    pecl install xdebug
docker-compose.yml
version: '3'

services:
  php:
    build: ./php
    ports:
      - '80:80'
    volumes:
      - ./php/html:/var/www/html
      - ./php/conf/php.ini:/usr/local/etc/php/php.ini
      - ./php/log/xdebug:/var/log/xdebug
php.ini
[Date]
date.timezone = "Asia/Tokyo"

[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

[xdebug]
; xdebugのインストール先を指定(Dockerコンテナ内)
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20170718/xdebug.so
xdebug.remote_enable=1
xdebug.remote_autostart=1
; デバッグで使用するポートを指定(デフォルト値)
xdebug.remote_port=9222
; Dockerコンテナ内部から見たホストを指定
xdebug.remote_host=host.docker.internal
; ログ出力先
xdebug.remote_log=/var/log/xdebug/xdebug.log
xdebug.remote_connect_back=1
launch.json
{
  "version": "0.1.0",
  "configurations": [
    {
      "name": "Listen for XDebug",
      "type": "php",
      "request": "launch",
      "port": 9222,
      "pathMappings": {
        // Dockerコンテナのdocument root : 開発環境のdocument root
        "/var/www/html":"${workspaceFolder}/php/html" 
      }
    }
  ]
}
index.php
<?php

echo 'Hello World<br>';

はまった点

・Dockerの立ち上げから、HTTPへのアクセスまではすんなりいったが、ブレイクポイントで止まらなかった。結果、launch.jsonのポートの設定を自分の環境で使用しているものに変更したら動きました。
・xdebugのインストール先を指定(Dockerコンテナ内)をphp.iniファイルに記入するのが抜けていたため動かなかった。※環境によってパスが変わるようであり、Dockerを立ち上げたときにコマンド上でインストールされたパスが確認できる。

参考にさせて頂いた記事

・Docker-composeのコマンド
https://qiita.com/okyk/items/a374ddb3f853d1688820
・構築方法
https://qiita.com/MasanoriIwakura/items/a310c75e6c5b347adf37

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

while構文

while構文

繰り返す条件を作るための初期化処理
while (繰り返す条件){
  繰り返したい処理
  更新処理
}

↓↓↓↓↓

$i = 1;
while ($i <= 365){
     print $i . PHP_EOL;
     $i = $i + 1;
}
  • 一番重要なところは「繰り返す条件」($i <= 365)
    • ◯◯が△△になったら繰り返してください、◯◯が△△ではなくなったら繰り返しをやめてください、といった条件を記述する
    • 上記の場合は『$iという変数の内容が365以下の間繰り返す』と言った条件になっている
  • $iは最初どういう状態なのか?
    • 「初期化処理」$i = 1;の部分で行われる
    • $i = 1として数字の1を代入しているので、最初の$iの状態は 1 であることがわかる
    • while構文の条件である『$iが365以下』に該当するので、while構文の中括弧に入って「繰り返したい処理」が行われる
    • while構文は「繰り返したい処理」が終わると、元の部分に戻るという性格がある
    • $iが365以下の場合は、画面に数字が表示された後、またwhile構文に戻ってくる
    • ここで更新処理を書かないと、$iには1が代入されたままとなり無限ループとなってしまう。
  • 更新処理
    • 繰り返す条件に使っている変数などは、最終的に条件から外れるような計算などを行う必要がある
    • 「更新処理」$i = $i + 1;
      • $i$i+1 を代入する。
    • 1 を画面に表示した後、$iには1+1である 2 が代入される
    • またwhile構文の最初に戻るので$iが365以下であることは変わらないが、$iの内容自体は変わっている。(1が2になっている)
    • 2 が画面に表示された後、$iは2+1である 3 が代入される
      • 3が画面に表示されて4・・・5・・・6と1ずつ増えていく
    • 364が画面に表示された後、365になった$iのままwhile構文に戻る。
      • 条件は「365以下」なので365も含まれる
    • 画面には365と表示され、$iが366になった後while構文に戻るが、この時点で条件から外れる。
    • 画面には365が表示されて処理が終わる。(条件から外れたので)

※参考:Udemy/Webサーバーサイドプログラミング入門

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