12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-02-21

問題のない例

以下のような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になってしまうのか...ということまではわからなかった。

12
7
2

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
12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?