Laravel Modelのupdateメソッドを読んでみる

## 目的
普段何気なく使用しているメソッドのコードを読んで、Laravelの理解を深める
今回はEloquentモデルのupdateメソッドを読んでいく。

### update

```php
    /**
     * Update the model in the database.
     *
     * @param  array  $attributes
     * @param  array  $options
     * @return bool
     */
    public function update(array $attributes = [], array $options = [])
    {
        if (! $this->exists) {
            return false;
        }

        return $this->fill($attributes)->save($options);
    }
```

## 読んでみる

1.`$this->exists`は、どこで定義しているのか。
→モデルがインスタンス化された時にexistsがセットされているようだ。
もし、モデルがインスタンス化されていなかったら、falseが返る。

```php
    /**
     * Create a new instance of the given model.
     *
     * @param  array  $attributes
     * @param  bool  $exists
     * @return static
     */
    public function newInstance($attributes = [], $exists = false)
    {
        // This method just provides a convenient way for us to generate fresh model
        // instances of this current model. It is particularly useful during the
        // hydration of new objects via the Eloquent query builder instances.
        $model = new static((array) $attributes);

        $model->exists = $exists;

        $model->setConnection(
            $this->getConnectionName()
        );

        $model->setTable($this->getTable());

        return $model;
    }
```

2.`fill`の中身は？

```php
    /**
     * Fill the model with an array of attributes.
     *
     * @param  array  $attributes
     * @return $this
     *
     * @throws \Illuminate\Database\Eloquent\MassAssignmentException
     */
    public function fill(array $attributes)
    {
        $totallyGuarded = $this->totallyGuarded();

        foreach ($this->fillableFromArray($attributes) as $key => $value) {
            $key = $this->removeTableFromKey($key);

            // The developers may choose to place some attributes in the "fillable" array
            // which means only those attributes may be set through mass assignment to
            // the model, and all others will just get ignored for security reasons.
            if ($this->isFillable($key)) {
                $this->setAttribute($key, $value);
            } elseif ($totallyGuarded) {
                throw new MassAssignmentException(sprintf(
                    'Add [%s] to fillable property to allow mass assignment on [%s].',
                    $key, get_class($this)
                ));
            }
        }

        return $this;
    }
```
ここでは、traitのGuardsAttributesの`fillableFromArray()`を使用して、配列の中のfillableであるキーを探し出してから繰り返し処理を行う。そのため、updateの配列にfillableに書いていないキーが入っていた場合は、updateされない。


例　
```php

class User extends Authenticatable
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name'
    ];
}


    $user->update([
        'sample' => 'aaa',
        'name' => 'jack',
    ]);
```

この場合は、sampleは無視され、nameのみupdateされる。


3.`save`の中身は？

```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;
    }

```
saveでupdateの第二引数を使用している。
`finishSave($option)`で`touch`というキーが配列の中にあるか調べている。

```php
    /**
     * Perform any actions that are necessary after the model is saved.
     *
     * @param  array  $options
     * @return void
     */
    protected function finishSave(array $options)
    {
        $this->fireModelEvent('saved', false);

        if ($this->isDirty() && ($options['touch'] ?? true)) {
            $this->touchOwners();
        }

        $this->syncOriginal();
    }
```

ちなみに`touch`は何をするものかというと、親リレーションのupdated_atを同時に更新するメソッドである。
子のモデルに touches プロパティを追加し使用する。

https://readouble.com/laravel/5.5/ja/eloquent-relationships.html

saveの引数の使い方
```php
$user->save([
    'touch' => false
]);

```
updateの第二引数にも、同じように配列を書いてあげるとよいでしょう。

#### 発見したこと👀
updateメソッドには、第二引数を渡すことができる。