目的
普段何気なく使用しているメソッドのコードを読んで、Laravelの理解を深める
今回はEloquentモデルのupdateメソッドを読んでいく。
update
/**
* 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が返る。
/**
* 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
の中身は?
/**
* 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されない。
例
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
の中身は?
/**
* 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
というキーが配列の中にあるか調べている。
/**
* 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 プロパティを追加し使用する。
saveの引数の使い方
$user->save([
'touch' => false
]);
updateの第二引数にも、同じように配列を書いてあげるとよいでしょう。
発見したこと👀
updateメソッドには、第二引数を渡すことができる。