LoginSignup
0
1

More than 1 year has passed since last update.

LaravelのtoArrayメソッドの実装を見てみる

Posted at

概要

LaravelのModelクラスに実装されているtoArrayメソッドの挙動が気になったので、元のコードを読んで仕様を噛み砕いていきます。

環境

Laravel v6.20.26

実際のコード

以下のコードが主となっています。
コメントも書いてあるのでさらにジャンプしたコードについては記載しません

呼び出し

// Illuminate\Database\Eloquent\Model;
public function toArray()
{
    return array_merge($this->attributesToArray(), $this->relationsToArray());
}

attributesの変換

前提として、LaravelのModelは内部にattributesという項目をもち、一般的なphpのclassのプロパティとは違う形で管理しています。
getXXAtributes系のメソッドはそのattributesから条件にあった項目を取り出しています。

以下の流れで取得・変換を行なっています。配列$attributesに全て追加・変更しています。

  1. $datesで定義したattributeの変換
  2. ミューテタ(get{アトリビュート名}Attributeで定義してプロパティのように扱えるやつ)の取得・変換($this->addMutatedAttributesToArray)
  3. $castsで定義された項目の変換。ミューテタが定義されているものはキャストされません。ひっかかるケースありそう。
  4. $appendsで定義された追加された項目の取得。
// => Illuminate\Database\Eloquent\Concerns\HasAttributes;
/**
 * Convert the model's attributes to an array.
 *
 * @return array
 */
public function attributesToArray()
{
    // If an attribute is a date, we will cast it to a string after converting it
    // to a DateTime / Carbon instance. This is so we will get some consistent
    // formatting while accessing attributes vs. arraying / JSONing a model.
    $attributes = $this->addDateAttributesToArray(
        $attributes = $this->getArrayableAttributes()
    );

    $attributes = $this->addMutatedAttributesToArray(
        $attributes, $mutatedAttributes = $this->getMutatedAttributes()
    );

    // Next we will handle any casts that have been setup for this model and cast
    // the values to their appropriate type. If the attribute has a mutator we
    // will not perform the cast on those attributes to avoid any confusion.
    $attributes = $this->addCastAttributesToArray(
        $attributes, $mutatedAttributes
    );

    // Here we will grab all of the appended, calculated attributes to this model
    // as these attributes are not really in the attributes array, but are run
    // when we need to array or JSON the model for convenience to the coder.
    foreach ($this->getArrayableAppends() as $key) {
        $attributes[$key] = $this->mutateAttributeForArray($key, null);
    }

    return $attributes;
}

relationsの変換

前提として、hasOneなどの関連性を定義したメソッドは、内部的に$relationsというプロパティで管理されています。$this->relationsをトリガーとしてロードが行われます。

流れ的には以下になります。

  1. Arrayableなrelationsを取得し、内容が条件が合致していれば$attributesに追加していく
    1. $valueの追加条件
      • Arrayableなインスタンスの場合 => 配列に変換して追加
      • nullの場合 => 追加しない
    2. $snakeAttributesの設定によっては項目名をスネークケースに変換(デフォルトはtrue)
// => Illuminate\Database\Eloquent\Concerns\HasAttributes;
/**
 * Get the model's relationships in array form.
 *
 * @return array
 */
public function relationsToArray()
{
    $attributes = [];

    foreach ($this->getArrayableRelations() as $key => $value) {
        // If the values implements the Arrayable interface we can just call this
        // toArray method on the instances which will convert both models and
        // collections to their proper array form and we'll set the values.
        if ($value instanceof Arrayable) {
            $relation = $value->toArray();
        }

        // If the value is null, we'll still go ahead and set it in this list of
        // attributes since null is used to represent empty relationships if
        // if it a has one or belongs to type relationships on the models.
        elseif (is_null($value)) {
            $relation = $value;
        }

        // If the relationships snake-casing is enabled, we will snake case this
        // key so that the relation attribute is snake cased in this returned
        // array to the developers, making this consistent with attributes.
        if (static::$snakeAttributes) {
            $key = Str::snake($key);
        }

        // If the relation value has been set, we will set it on this attributes
        // list for returning. If it was not arrayable or null, we'll not set
        // the value on the array because it is some type of invalid value.
        if (isset($relation) || is_null($value)) {
            $attributes[$key] = $relation;
        }

        unset($relation);
    }

    return $attributes;
}

まとめ

基本的には通常の呼び出し時などと変わらずキャストも行い、ミューテタやリレーションも取得・変換してくれることがわかりました。
バルクインサートなどを行う際はtoArrayメソッドを使用しますが、エラー対応等で苦戦したので自分用にまとめております。
誰かのお役に立てば幸いです。

0
1
0

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
0
1