PHP
laravel
Laravel5.3

【Laravel】Modelをsaveすると、そのインスタンスのidが0になることがある

More than 1 year has passed since last update.


問題のない例

以下のようなmigrationとmodelの場合、特に問題は起こらない。

php artisan make:migration create_samples_table

php artisan make:model Sample


  • create_samples_table.php

use Illuminate\Support\Facades\Schema;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateSamplesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/

public function up()
{
Schema::create('samples', function (Blueprint $table) {
$table->increments('id');
$table->string('content');
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/

public function down()
{
Schema::drop('samples');
}
}


  • Sample.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Sample extends Model
{
//
}


  • 使用例

$sample          = new Sample();

$sample->content = 'hoge';
$sample->save();

echo $sample->id; // 1


idがnullになる例

例えば、modelkeystringにしたいという場合。

migrationは以下のようになるだろう。

use Illuminate\Support\Facades\Schema;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateSamplesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/

public function up()
{
Schema::create('samples', function (Blueprint $table) {
$table->string('id')->unique(); //変更
$table->string('content');
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/

public function down()
{
Schema::drop('samples');
}
}

これをこのまま使用すると以下のようにidに0が格納されてしまう。

(データベースには正しくida1234567が格納されている)

$sample          = new Sample();

$sample->id = 'a1234567';
$sample->content = 'hoge';
$sample->save();

echo $sample->id; // 0


解決策

おそらくだがsave時にint型で自動増分させる処理の際に、0が格納されてしまうのだろう。

なので、Modelのプロパティを以下のように設定してあげれば解決できる。


  • Sample.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Sample extends Model
{
/**
* The "type" of the auto-incrementing ID.
*
* @var string
*/

protected $keyType = 'string';

/**
* モデルの主キーを自動増分させるか否か
*
* @var boolean
*/

public $incrementing = false;
}


  • 使用例

$sample          = new Sample();

$sample->id = 'a1234567';
$sample->content = 'hoge';
$sample->save();

echo $sample->id; // a1234567


原因?(追記)

$incrementing = trueとなっていると、以下のprocessInsertGetIdが実行される。

public function processInsertGetId(Builder $query, $sql, $values, $sequence = null)

{
$query->getConnection()->insert($sql, $values);
$id = $query->getConnection()->getPdo()->lastInsertId($sequence);
return is_numeric($id) ? (int) $id : $id;
}

つまり、save時にインサートが行われ、その後最新のIdを取得してきている。

この処理の間に$idが0となってしまっているようだが、

具体的になぜ0になってしまうのか...ということまではわからなかった。