Laravelのcreate()、save()、insert()の違い

# 各メソッドの挙動の違い
DB保存の方法はいくつかあるが、どういう違いがあるかを把握せずに使っていたため、主に使う`create()`、`save()`、`insert()`の違いをまとめていく。

## create()
指定された属性を持つ新しいモデルインスタンスを作成し、データベースに保存してからそのインスタンスを返す。

```php
$user = User::create(['name' => 'hoge']);
```

vendorの中を見にいくと以下のようなコードが書かれている。

```php:vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
/*
 * Save a new model and return the instance.
 *
 * @param  array  $attributes
 * @return \Illuminate\Database\Eloquent\Model|$this
 */
public function create(array $attributes = [])
{
    return tap($this->newModelInstance($attributes), function ($instance) {
        $instance->save();
    });
}
```

## save()
モデルのインスタンスをデータベースに保存する。`create()`と異なり、保存後インスタンスは返さず、保存が成功したかどうかを示すブール値を返す。

また、モデルが既にデータベースに存在する場合（モデルがデータベースから取得された場合や、新しいレコードがデータベースに挿入された後等）は更新を行い、存在しない場合は新規保存を行う。

```php
$user = new User();
$user->name = $request->name;
$user->save();
```

vendorの中を見にいくと以下のようなコードが書かれている。

```php:vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
/*
 * Save the model to the database.
 *
 * @param  array  $options
 * @return bool
 */
public function save(array $options = [])
{
    $query = $this->newModelQuery();

    // If the "saving" event returns false we'll bail out of the save and return
    // false, indicating that the save failed. This provides a chance for any
    // listeners to cancel save operations if validations fail or whatever.
    if ($this->fireModelEvent('saving') === false) {
        return false;
    }

    // If the model already exists in the database we can just update our record
    // that is already in this database using the current IDs in this "where"
    // clause to only update this model. Otherwise, we'll just insert them.
    if ($this->exists) {
        $saved = $this->isDirty() ?
                    $this->performUpdate($query) : true;
    }

    // If the model is brand new, we'll insert it into our database and set the
    // ID attribute on the model to the value of the newly inserted row's ID
    // which is typically an auto-increment value managed by the database.
    else {
        $saved = $this->performInsert($query);

        if (! $this->getConnectionName() &&
            $connection = $query->getConnection()) {
            $this->setConnection($connection->getName());
        }
    }

    // If the model is successfully saved, we need to do a few more things once
    // that is done. We will call the "saved" method here to run any actions
    // we need to happen after a model gets successfully saved right here.
    if ($saved) {
        $this->finishSave($options);
    }

    return $saved;
}
```

## insert()
複数のレコードを一度に保存する。直接SQLのINSERT文を実行するため、タイムスタンプの更新等は行わない。また、`fillable`のチェックが行われないため、複数代入による脆弱性が発生する可能性もある。

```php
User::insert([['name' => 'hoge']]);
```

vendorの中を見にいくと以下のようなコードが書かれている。

```php:vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
/*
 * Save a new model and return the instance.
 *
 * @param  array  $attributes
 * @return \Illuminate\Database\Eloquent\Model|$this
 */
public function create(array $attributes = [])
{
    return tap($this->newModelInstance($attributes), function ($instance) {
        $instance->save();
    });
}
```

# まとめ
- `create()`：新しいモデルインスタンスを作成、データベースに保存してそのインスタンスを返す
- `save()`：既存のモデルインスタンスをデータベースに保存する。新しいインスタンスを保存することも可能
- `insert()`：複数のレコードを一度に挿入する。fillable属性のチェックがされないので使い時に注意