laravel5.5 源码解析之belongToMany toggle

场景

. 多对多的关系中经常需要用到的一种方式
. 实例   Question Model and Follower Model(问题关注者)
  假设点击一个按钮,则如果用户已经是关注者,则取消关注 否则成为关注者

分析

1.  belongsToMany 在哪里实现了toggle?  内部trait实现
class BelongsToMany extends Relation
{
    use Concerns\InteractsWithPivotTable;
}
2.  toggle实现的过程 :
   . 将传入的参数全部转成Key为id的数组 (传入的参数可能是Model Collection BaseCollection 或者本身就是id 数组或者字符串)
   . 和已经存在的关系(id array)找交集 $detch,交集执行detach
   . 和已经存在的关系(id array)找相对补集  执行attach 
     这里的实现有点意思  采用的方式是在 解析出来的id array中找$deatch补集
         $attach = array_diff_key($records, array_flip($detach));
  /**
     * Toggles a model (or models) from the parent.
     *
     * Each existing model is detached, and non existing ones are attached.
     *
     * @param  mixed  $ids
     * @param  bool   $touch
     * @return array
     */
    public function toggle($ids, $touch = true)
    {
        $changes = [
            'attached' => [], 'detached' => [],
        ];

        $records = $this->formatRecordsList($this->parseIds($ids));

        // Next, we will determine which IDs should get removed from the join table by
        // checking which of the given ID/records is in the list of current records
        // and removing all of those rows from this "intermediate" joining table.
        $detach = array_values(array_intersect(
            $this->newPivotQuery()->pluck($this->relatedPivotKey)->all(),
            array_keys($records)
        ));

        if (count($detach) > 0) {
            $this->detach($detach, false);

            $changes['detached'] = $this->castKeys($detach);
        }

        // Finally, for all of the records which were not "detached", we'll attach the
        // records into the intermediate table. Then, we will add those attaches to
        // this change list and get ready to return these results to the callers.
        $attach = array_diff_key($records, array_flip($detach));

        if (count($attach) > 0) {
            $this->attach($attach, [], false);

            $changes['attached'] = array_keys($attach);
        }

        // Once we have finished attaching or detaching the records, we will see if we
        // have done any attaching or detaching, and if we have we will touch these
        // relationships if they are configured to touch on any database updates.
        if ($touch && (count($changes['attached']) ||
                       count($changes['detached']))) {
            $this->touchIfTouching();
        }

        return $changes;
    }

你可能感兴趣的:(laravel)