ドドスコblog

Laravel5.5 apiを作ったけどjsonデータが文字化けする

LaravelでAPIを作ってみたらjsonの中身が文字化けしていた。

{"id":1,"name":"\u682a\u5f0f\u4f1a\u793e \u6749\u5c71"}

原因

unicode で日本語がエスケープされる。

解決方法

unicodeエスケープされないようにする

問題の文字化けjsonレスポンス

return response()->json(
    ['name' => 'Tanaka']
);

jsonレスポンスを文字化けしないように変更

return response()->json(
    ['name' => 'Tanaka'],
    200,
    [],
    JSON_UNESCAPED_UNICODE
);

MySQL 8.0でmigrationエラーが発生した時の解決方法

ローカル環境ではMySQL5.6を使っていたのですが、 サーバーにデプロイ時に、MySQL8.0が出たと聞いて面白がって導入して痛い目をみました。 いつものようにphp artisan migrateでテーブルを作成しようとしたら

lluminate\Database\QueryException  : SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client

と表示され、未知の認証方法を要求されたときて困惑しました。

これはLaravel側の問題でした。 MySQL8.0からはユーザー作成時のデフォルトの認証設定で、 caching_sha2_passwordという方式を取り始めましたが、 Laravel5.5ではそれには対応していないので、未知の認証方法であるとエラーが出たみたいです。

解決方法としましては、 * MySQLのバージョンを下げる。 * MySQL8.0のユーザーの認証方法をLarvelでも対応できるものに変更する。

今回は後者で解決しました。 まず、MySQLの/etc/my.cnfにデフォルトの認証方法を変更する処理を加えます。

default_authentication_plugin=mysql_native_password

そして、mysqlを再起動すれば変更は反映されます。

service mysqld restart

もしユーザーを作成済みでしたら、削除してもう一度作り直せば、解決できます。

結論

今回は認証だけだったので問題解決に時間はかかりませんでしたが、 ローカルと違う環境にむやみに挑戦するのはやめましょう。

Laravel Bladeで改行する方法

inputタグやtextareaに文字列を出力すると改行はされますが、 それ以外のアンカーなどに出力すると改行されずに表示されます。 解決策として

<a>{!! nl2br(e($form->event_info)) !!}</a>

と書きます。 このアンカーに使われている三つの機能を解説します。

データのエスケープ
{!! !!}

Bladeの基本として{{}}内に変数を置いて変数の中身を表示すると学びましたが、{!! !!}も同じ機能を持っています。 違いはデータをエスケープするかどうかです。

aaaaと表示される。改行され下に空白ができる。
<a>{!! 'aaaa</br>' !!}</a>
aaaa</br>と表示される。
<a>{{ 'aaaa</br>' }}</a>
改行文字の前にbrタグを挿入する
nl2br()

アンカーは改行を認識せずに表示するため、改行コードがある文字列を一列に表示してしまいますが、 nl2br()を使うと改行コードの前にbrタグが挿入され改行されます。

htmlタグ無効化?
e()

これはLaravelのヘルパー関数で、文字列のhtmlタグを無効化する?機能があります。 変なhtmlを生成されてデザイン崩れを防ぐ為に存在すると思います。

The e function runs PHP's htmlspecialchars function with the double_encode option set to false:

ヘルパ関数 5.1 Laravel

qiita.com

datetime-localに初期値を設定しても値が反映されない時の解決法。

今回の内容はHTMLに関するものです。

datetime-localというHTMLのタグがありますが、サーバーサイドでvalueに初期値を設定しても反映されなかった話です。 ブラウザでソースを見ても

<input type="datetime-local" value="2016-12-23 02:00:00">

というように値は設定されていますが、ブラウザに値は反映されませんでした。 ブラウザで値を入力したものと、サーバー側で初期値を設定したものをくらべても

{{--サーバー側で値を設定、表示されない--}}
<input type="datetime-local" value="2016-12-23 02:00:00">
{{--ブラウザで値を設定、表示される--}}
<input type="datetime-local" value="2016-12-23 02:00:00">

ソースは同じなのに値は反映されません。 調べたところ日付と時間の間に"T"をおく必要があるみたいでした。

{{--valueにはLaravelのBladeの機能を使っています。--}}
<input type="datetime-local" value="{{str_replace(" ", "T", $event->open_day)}}">

datetime-localはブラウザごとに動きがかなり違うみたいでjqueryのtimepickerなどのスクリプトで入力欄を作った方がいいみたいです。

developer.mozilla.org

Laravel テーブルにinsertしたデータのIDなどを取得する方法

テーブルのIDはほとんどの場合、AUTO_INCREMENTを指定してシーケンス番号を割り振るのが普通ですが、そうした場合追加したデータのIDを調べるのにinsertした後、slect文でIDを検索する処理を書く必要があります。 LaravelではinsertGetIdを使うことでそのような手間はかけずにIDを取得できます。

// 通常のインサート処理
DB::table('テーブル名')->insert(['name' => '田中', ]);
// インサートと同時にIDを取得する
$id = DB::table('テーブル名')->insertGetId(['name' => '田中', ]);

ただし、上記のようなinsertGetIdでは「id」という列名の値しか取得できません。 idの役割がある列名がcustomer_idやevent_idといったものや、全然違う列の値を取得したい場合は第二引数に列名を追加します。

// インサートと同時に特定の列の値を取得する
$id = DB::table('テーブル名')->insertGetId(['name' => '田中', ], 'customer_id');

こういう機能は他のプログラミング言語でもinsertGetIdみたいな名前でよくあるので覚えておくこと。

Laravel paginateの注意点

Eloquent ORMでテーブルのモデルを作ることを前提とする。

// Eventはモデル
$items = Event::latest()->paginate(12);

latest()を使って降順にデータを取得するが、対象のテーブルにcreated_at列がないとエラーになる。 ちなみにマイグレーションファイルに$table->timestamps()を記述すればcreated_at, updated_at列は自動で作られる。

どうやら select * from テーブル名 order by created_at desc というクエリが走って取得しているらしい。

対処法として、テーブルにcreated_at列を付け加えるか、latest()機能に相当するものを自作する。 今回は自作する方法を紹介する。

$items = Event::orderBy('列名', 'desc')->paginate(12);