1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Laravel] assertionDatabaseHasメソッドでなぜかエスケープされてしまう件について

Posted at

「それでも、と言い続けろ」
マリーダクルスの言い付けを守り続けています。

  • 朝起きたけどクソ寒いとき
  • ベンチプレスで潰れそうなとき
  • 有酸素運動が憂鬱なとき
  • エラーが全く直らないとき
  • 採用面接で落とされたとき
  • エヴァの時短駆け抜けたとき
  • タバコ、エナジードリンクの誘惑に負けそうなとき

自分に負けそうなときでも、マリーダさんの言い付けを思い出し、自分を奮い立たせています。
そう、僕はユニコーンガンダムのパイロットなのです。

謎のエスケープ、ふざけんな

postで送信した値がデータベースに保存されているかどうかを確認するメソッドがassertionDatabaseHas()です。
以下のような値を送りました。

$response = $this->actingAs($user)->post('/mypage/profile',[
    'name' => "変更後ネーム",
    'postcode' => "1110032",
    'address' => "東京都台東区浅草2-3-1",
    'building' => "浅草寺",
]);

これを確認しようとすると、こんな感じにエンコードした値を比較しようとします。

    'name' => "変更後ネーム",
    'postcode' => "1110032",
    'address' => "\u6771\u4eac\u90fd\u53f0\u6771\u533a\u6d45\u83492-3-1",
    'building' => "\u6d45\u8349\u5bfa",

住所と建物名のプロパティがエンコードされているようです。
Laravelはプライバシーに気を遣った良い仕様だなあ、な訳あるか。
一致するわけねえだろ。

そもそものコードを変えてしまおう

以下の記事を参考にしました。本当にありがとうございます。
https://zenn.dev/nshiro/articles/2ab61e562f8584

僕もこの人のようにOSSのコントリビュータになりたいものです。

僕がしたことは以下の順序です。

  1. エンコード部分を書き換えたクラス作成
  2. サービスコンテナに登録

まずは以下のクラスを作成しました。
これはパッケージにあるassertionDatabaseHasメソッドのエンコード部分のみを抜き出し、少し編集を加えています。

<?php

namespace Tests;

use Illuminate\Testing\Constraints\HasInDatabase as PackageHasInDatabase;

class HasInDatabase extends PackageHasInDatabase
{
    public function failureDescription($table): string
    {
        return sprintf(
            "a row in the table [%s] matches the attributes %s.\n\n%s",
            $table,
            //以下のJSON_UNESCAPED_UNICODE
            $this->toString(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),
            $this->getAdditionalInfo($table)
        );
    }

    protected function getAdditionalInfo($table)
    {
        $query = $this->database->table($table);

        $similarResults = $query->where(
            array_key_first($this->data),
            $this->data[array_key_first($this->data)]
        )->limit($this->show)->get();

        if ($similarResults->isNotEmpty()) {
            //以下のJSON_UNESCAPED_UNICODE
            $description = 'Found similar results: ' . json_encode($similarResults, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        } else {
            $query = $this->database->table($table);

            $results = $query->limit($this->show)->get();

            if ($results->isEmpty()) {
                return 'The table is empty.';
            }
            //以下のJSON_UNESCAPED_UNICODE
            $description = 'Found: ' . json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        }

        if ($query->count() > $this->show) {
            $description .= sprintf(' and %s others', $query->count() - $this->show);
        }

        return $description;
    }

}

コメントアウトをしている3箇所が変更を加えた箇所です。
Unicode文字をエスケープさせないようにするオプションです。

他にも大事なのが継承しているPackageHasInDatabase(HasInDatabase)クラスです。これがパッケージにあるクラスです。元々使われるはずのクラスを継承しないと必ずエラーが出力されます。
継承しないと、あまりにも別のクラスが呼び出されると、プロパティやメソッドなどのあらゆる要素が不十分である可能性があるためです。
わかりやすい例で言うと、「マッチングアプリで写真と全く違う女の子が来ること」と同じです。
Laravel側からすると、「誰やねんお前、その面見せんな」とでも言わんばかり。

次にサービスコンテナへの登録です。

//AppServiceProvider.php の registerメソッド内
$this->app->bind(PackageHasInDatabase::class, HasInDatabase::class);

これをすることで、パッケージ内の元々使われるクラスが呼び出された時に、自分が編集を少し加えたクラスが呼び出されるよ、となります。

これでエスケープ問題は解決しました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?