Ikeda's Blog

LaravelでDBから取得した主キーがおかしい

前提条件

以下のような設定でテーブルを作成していた。
先に言ってしまうと、主キーが文字列なことが問題点。

Schema::create('members', function (Blueprint $table) {
    $table->string('id', 50)->primary();
    $table->text('name');
    $table->timestamps();
    $table->softDeletes();
});

データ内容

id name
a.ikeda Ikeda A
b.ikeda Ikeda B

データを取得し、内容を表示すると……

dump(Member::all()->toArray());
array:2 [▼
  0 => array:5 [▼
    "id" => 0
    "memo" => "Ikeda A"
  ]
  1 => array:5 [▼
    "id" => 0
    "memo" => "Ikeda B"
  ]
]

idが「0」になってしまう。

原因

ドキュメントの Eloquent ORM > Eloquentの準備にある、「主キー」

さらに、Eloquentは、主キーが増分整数値であることも想定しています。これは、Eloquentが主キーを自動的に整数にキャストすることを意味します。

そのまま書いてありました。主キーを整数にキャストしてしまうため、文字列だけ入れていると「0」になってしまうのでした。
そして、解決方法も同じように書いてあります。

非インクリメントまたは非数値の主キーを使用する場合は、モデルにpublicの$incrementingプロパティを定義し、falseをセットする必要があります。

モデルの主キーが整数でない場合は、モデルにprotectedな$keyTypeプロパティを定義する必要があります。このプロパティの値はstringにする必要があります。

の2箇所です。

対策

app\Models\*****.phpに、以下の記述を追加することで解決します。

<?php

class Member extends Model
{
    public $incrementing = false; // モデルのIDを自動増分するか
    protected $keyType = 'string'; // IDのデータ型

    // 以下省略
}

PHPで数値文字参照

はじめに

「PHP 数値文字参照」なんかで検索すると出てくる手法が不完全なので、備忘録。
mb_convert_encodingを利用する方法を記載する記事が多いが、記号が変換できない。

mb_convert_encodingで変換してみる

以下のコードの結果で、ひらがなや全角アルファベットは変換できているが、「$%&」などの記号がそのままになってしまっているのがわかる。
※𪘂𪘚𪚲は、UTF-8の4バイト文字。

$before = '$%&あいうABC𪘂𪘚𪚲';
$after = mb_convert_encoding($before, 'HTML-ENTITIES', 'UTF-8');
var_dump($after); // string(78) "$%&&#12354;&#12356;&#12358;&#65313;&#65314;&#65315;&#173570;&#173594;&#173746;"

mb_encode_numericentityで変換してみる

mb_encode_numericentity
こちらであれば、記号も無事に数値文字参照へと変換できる。

$before = '$%&あいうABC𪘂𪘚𪚲';
$map = [0, 0x10FFFF, 0, 0xFFFFFF];
$after = mb_encode_numericentity($before, $map, 'UTF-8');
var_dump($after); // string(90) "&#36;&#37;&#38;&#12354;&#12356;&#12358;&#65313;&#65314;&#65315;&#173570;&#173594;&#173746;"

変換結果をHTMLで表示すれば、うまくいったことがわかる

■ source

&#36;&#37;&#38;&#12354;&#12356;&#12358;&#65313;&#65314;&#65315;&#173570;&#173594;&#173746;

■ result
$%&あいうABC𪘂𪘚𪚲

Laravelに認証機能を導入(Laravel Fortify)

概要

とあるレンタルサーバに、Laravelで作ったWEBアプリをリリースしようとしたら、npmが使えない事態が発生。
Laravel Jetstreamを使っていたので、構築段階でコケる状態になってしまった。
代替手段として、Laravel Fortifyを使ったので、導入方法の備忘録。

コマンド実行

composer require laravel/fortify
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"
php artisan migrate

config

config/app.phpに、以下を追加します。

App\Providers\FortifyServiceProvider::class,

登録、ログインページの定義

app/Providers/FortifyServiceProvider.phpを編集します。

<?php

// ... 省略 ...

class FortifyServiceProvider extends ServiceProvider
{
    // ... 省略 ...

    public function boot()
    {
        // ... 省略 ...

        // 登録ページは、resources/views/auth/register.blade.phpを表示する
        Fortify::registerView(function () {
            return view('auth.register');
        });

        // ログインページは、resources/views/auth/login.blade.phpを表示する
        Fortify::loginView(function () {
            return view('auth.login');
        });
    }
}

view

登録ページ

登録時に必要なのは、「名前(name)」「メールアドレス(email)」「パスワード(password)」「パスワード再入力(password_confirmation)」の4項目です。
それさえあれば良いので、以下だけでも動きます。

<form method="post" action="{{route('register')}}">
    @csrf
    name:<input type="text" name="name"><br />
    mail:<input type="text" name="email"><br />
    pass:<input type="password" name="password"><br />
    pass:<input type="password" name="password_confirmation"><br />
    <button type="submit">登録</button>
</form>

ログインページ

こちらは、「メールアドレス(email)」「パスワード(password)」があれば良いので、更にシンプル。

<form method="post" action="{{route('login')}}">
    @csrf
    mail:<input type="text" name="email"><br />
    pass:<input type="password" name="password"><br />
    <button type="submit">ログイン</button>
</form>

動作確認

http://(ドメイン)/registerから登録し、
http://(ドメイン)/loginからログインできるかを確認。

備考:ログイン後の遷移先を指定

app/Providers/RouteServiceProvider.phpにある、HOMEの値を変更すればOK。

PHPから、GoogleAnalyticsプロパティ4にイベントを送信する

概要

公式ドキュメント
PHPからAnalyticsにイベントを送信しようとしても、上手く行かずにマハったので備忘録。

コード

// アカウントに関連付く情報
$api_secret = 'xxxxxxxxxx';
$measurement_id = 'yyyyyyyyyy';

// ユーザごとに設定される値
$client_id = '999999.999999';

// 送信したいイベント
$events = [
    'name' => 'click',
    'param' => [
        'id' => 'ABC001',
    ],
];

$data = [
    'client_id' => $client_id,
    'events' => $events
];

$data_string = json_encode($data);
$post_url = 'https://www.google-analytics.com/mp/collect?api_secret=' . $api_secret . '&measurement_id=' . $measurement_id;
$ch = curl_init($post_url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $post_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
curl_setopt($ch, CURLOPT_POST, TRUE);
$result = curl_exec($ch);

エルビス演算子とNull合体演算子で、それぞれの挙動の違い

エルビス演算子(PHP5.3以降)

$val = ($_GET['value']) ?: 'default';
var_dump($_GET['value']) var_dump($val) 備考
NULL string(7) "default" Notice: Undefined index 発生
string(0) "" string(7) "default" -
string(3) "aaa" string(3) "aaa" -

Null合体演算子(PHP7.0以降)

$val = ($_GET['value']) ?? 'default';
var_dump($_GET['value']) var_dump($val) 備考
NULL string(7) "default" -
string(0) "" string(0) "" -
string(3) "aaa" string(3) "aaa" -