671 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			671 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace Illuminate\Database\Eloquent\Relations\Concerns;
 | 
						|
 | 
						|
use Illuminate\Database\Eloquent\Collection;
 | 
						|
use Illuminate\Database\Eloquent\Model;
 | 
						|
use Illuminate\Database\Eloquent\Relations\Pivot;
 | 
						|
use Illuminate\Support\Collection as BaseCollection;
 | 
						|
 | 
						|
trait InteractsWithPivotTable
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * 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;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sync the intermediate tables with a list of IDs without detaching.
 | 
						|
     *
 | 
						|
     * @param  \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array  $ids
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function syncWithoutDetaching($ids)
 | 
						|
    {
 | 
						|
        return $this->sync($ids, false);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sync the intermediate tables with a list of IDs or collection of models.
 | 
						|
     *
 | 
						|
     * @param  \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array  $ids
 | 
						|
     * @param  bool  $detaching
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function sync($ids, $detaching = true)
 | 
						|
    {
 | 
						|
        $changes = [
 | 
						|
            'attached' => [], 'detached' => [], 'updated' => [],
 | 
						|
        ];
 | 
						|
 | 
						|
        // First we need to attach any of the associated models that are not currently
 | 
						|
        // in this joining table. We'll spin through the given IDs, checking to see
 | 
						|
        // if they exist in the array of current ones, and if not we will insert.
 | 
						|
        $current = $this->getCurrentlyAttachedPivots()
 | 
						|
                        ->pluck($this->relatedPivotKey)->all();
 | 
						|
 | 
						|
        $detach = array_diff($current, array_keys(
 | 
						|
            $records = $this->formatRecordsList($this->parseIds($ids))
 | 
						|
        ));
 | 
						|
 | 
						|
        // Next, we will take the differences of the currents and given IDs and detach
 | 
						|
        // all of the entities that exist in the "current" array but are not in the
 | 
						|
        // array of the new IDs given to the method which will complete the sync.
 | 
						|
        if ($detaching && count($detach) > 0) {
 | 
						|
            $this->detach($detach);
 | 
						|
 | 
						|
            $changes['detached'] = $this->castKeys($detach);
 | 
						|
        }
 | 
						|
 | 
						|
        // Now we are finally ready to attach the new records. Note that we'll disable
 | 
						|
        // touching until after the entire operation is complete so we don't fire a
 | 
						|
        // ton of touch operations until we are totally done syncing the records.
 | 
						|
        $changes = array_merge(
 | 
						|
            $changes, $this->attachNew($records, $current, false)
 | 
						|
        );
 | 
						|
 | 
						|
        // 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 (count($changes['attached']) ||
 | 
						|
            count($changes['updated'])) {
 | 
						|
            $this->touchIfTouching();
 | 
						|
        }
 | 
						|
 | 
						|
        return $changes;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Format the sync / toggle record list so that it is keyed by ID.
 | 
						|
     *
 | 
						|
     * @param  array  $records
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function formatRecordsList(array $records)
 | 
						|
    {
 | 
						|
        return collect($records)->mapWithKeys(function ($attributes, $id) {
 | 
						|
            if (! is_array($attributes)) {
 | 
						|
                [$id, $attributes] = [$attributes, []];
 | 
						|
            }
 | 
						|
 | 
						|
            return [$id => $attributes];
 | 
						|
        })->all();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Attach all of the records that aren't in the given current records.
 | 
						|
     *
 | 
						|
     * @param  array  $records
 | 
						|
     * @param  array  $current
 | 
						|
     * @param  bool  $touch
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function attachNew(array $records, array $current, $touch = true)
 | 
						|
    {
 | 
						|
        $changes = ['attached' => [], 'updated' => []];
 | 
						|
 | 
						|
        foreach ($records as $id => $attributes) {
 | 
						|
            // If the ID is not in the list of existing pivot IDs, we will insert a new pivot
 | 
						|
            // record, otherwise, we will just update this existing record on this joining
 | 
						|
            // table, so that the developers will easily update these records pain free.
 | 
						|
            if (! in_array($id, $current)) {
 | 
						|
                $this->attach($id, $attributes, $touch);
 | 
						|
 | 
						|
                $changes['attached'][] = $this->castKey($id);
 | 
						|
            }
 | 
						|
 | 
						|
            // Now we'll try to update an existing pivot record with the attributes that were
 | 
						|
            // given to the method. If the model is actually updated we will add it to the
 | 
						|
            // list of updated pivot records so we return them back out to the consumer.
 | 
						|
            elseif (count($attributes) > 0 &&
 | 
						|
                $this->updateExistingPivot($id, $attributes, $touch)) {
 | 
						|
                $changes['updated'][] = $this->castKey($id);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $changes;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Update an existing pivot record on the table.
 | 
						|
     *
 | 
						|
     * @param  mixed  $id
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @param  bool  $touch
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    public function updateExistingPivot($id, array $attributes, $touch = true)
 | 
						|
    {
 | 
						|
        if ($this->using &&
 | 
						|
            empty($this->pivotWheres) &&
 | 
						|
            empty($this->pivotWhereIns) &&
 | 
						|
            empty($this->pivotWhereNulls)) {
 | 
						|
            return $this->updateExistingPivotUsingCustomClass($id, $attributes, $touch);
 | 
						|
        }
 | 
						|
 | 
						|
        if (in_array($this->updatedAt(), $this->pivotColumns)) {
 | 
						|
            $attributes = $this->addTimestampsToAttachment($attributes, true);
 | 
						|
        }
 | 
						|
 | 
						|
        $updated = $this->newPivotStatementForId($this->parseId($id))->update(
 | 
						|
            $this->castAttributes($attributes)
 | 
						|
        );
 | 
						|
 | 
						|
        if ($touch) {
 | 
						|
            $this->touchIfTouching();
 | 
						|
        }
 | 
						|
 | 
						|
        return $updated;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Update an existing pivot record on the table via a custom class.
 | 
						|
     *
 | 
						|
     * @param  mixed  $id
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @param  bool  $touch
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    protected function updateExistingPivotUsingCustomClass($id, array $attributes, $touch)
 | 
						|
    {
 | 
						|
        $pivot = $this->getCurrentlyAttachedPivots()
 | 
						|
                    ->where($this->foreignPivotKey, $this->parent->{$this->parentKey})
 | 
						|
                    ->where($this->relatedPivotKey, $this->parseId($id))
 | 
						|
                    ->first();
 | 
						|
 | 
						|
        $updated = $pivot ? $pivot->fill($attributes)->isDirty() : false;
 | 
						|
 | 
						|
        if ($updated) {
 | 
						|
            $pivot->save();
 | 
						|
        }
 | 
						|
 | 
						|
        if ($touch) {
 | 
						|
            $this->touchIfTouching();
 | 
						|
        }
 | 
						|
 | 
						|
        return (int) $updated;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Attach a model to the parent.
 | 
						|
     *
 | 
						|
     * @param  mixed  $id
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @param  bool  $touch
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function attach($id, array $attributes = [], $touch = true)
 | 
						|
    {
 | 
						|
        if ($this->using) {
 | 
						|
            $this->attachUsingCustomClass($id, $attributes);
 | 
						|
        } else {
 | 
						|
            // Here we will insert the attachment records into the pivot table. Once we have
 | 
						|
            // inserted the records, we will touch the relationships if necessary and the
 | 
						|
            // function will return. We can parse the IDs before inserting the records.
 | 
						|
            $this->newPivotStatement()->insert($this->formatAttachRecords(
 | 
						|
                $this->parseIds($id), $attributes
 | 
						|
            ));
 | 
						|
        }
 | 
						|
 | 
						|
        if ($touch) {
 | 
						|
            $this->touchIfTouching();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Attach a model to the parent using a custom class.
 | 
						|
     *
 | 
						|
     * @param  mixed  $id
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    protected function attachUsingCustomClass($id, array $attributes)
 | 
						|
    {
 | 
						|
        $records = $this->formatAttachRecords(
 | 
						|
            $this->parseIds($id), $attributes
 | 
						|
        );
 | 
						|
 | 
						|
        foreach ($records as $record) {
 | 
						|
            $this->newPivot($record, false)->save();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create an array of records to insert into the pivot table.
 | 
						|
     *
 | 
						|
     * @param  array  $ids
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function formatAttachRecords($ids, array $attributes)
 | 
						|
    {
 | 
						|
        $records = [];
 | 
						|
 | 
						|
        $hasTimestamps = ($this->hasPivotColumn($this->createdAt()) ||
 | 
						|
                  $this->hasPivotColumn($this->updatedAt()));
 | 
						|
 | 
						|
        // To create the attachment records, we will simply spin through the IDs given
 | 
						|
        // and create a new record to insert for each ID. Each ID may actually be a
 | 
						|
        // key in the array, with extra attributes to be placed in other columns.
 | 
						|
        foreach ($ids as $key => $value) {
 | 
						|
            $records[] = $this->formatAttachRecord(
 | 
						|
                $key, $value, $attributes, $hasTimestamps
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        return $records;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a full attachment record payload.
 | 
						|
     *
 | 
						|
     * @param  int  $key
 | 
						|
     * @param  mixed  $value
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @param  bool  $hasTimestamps
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function formatAttachRecord($key, $value, $attributes, $hasTimestamps)
 | 
						|
    {
 | 
						|
        [$id, $attributes] = $this->extractAttachIdAndAttributes($key, $value, $attributes);
 | 
						|
 | 
						|
        return array_merge(
 | 
						|
            $this->baseAttachRecord($id, $hasTimestamps), $this->castAttributes($attributes)
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the attach record ID and extra attributes.
 | 
						|
     *
 | 
						|
     * @param  mixed  $key
 | 
						|
     * @param  mixed  $value
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function extractAttachIdAndAttributes($key, $value, array $attributes)
 | 
						|
    {
 | 
						|
        return is_array($value)
 | 
						|
                    ? [$key, array_merge($value, $attributes)]
 | 
						|
                    : [$value, $attributes];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a new pivot attachment record.
 | 
						|
     *
 | 
						|
     * @param  int  $id
 | 
						|
     * @param  bool  $timed
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function baseAttachRecord($id, $timed)
 | 
						|
    {
 | 
						|
        $record[$this->relatedPivotKey] = $id;
 | 
						|
 | 
						|
        $record[$this->foreignPivotKey] = $this->parent->{$this->parentKey};
 | 
						|
 | 
						|
        // If the record needs to have creation and update timestamps, we will make
 | 
						|
        // them by calling the parent model's "freshTimestamp" method which will
 | 
						|
        // provide us with a fresh timestamp in this model's preferred format.
 | 
						|
        if ($timed) {
 | 
						|
            $record = $this->addTimestampsToAttachment($record);
 | 
						|
        }
 | 
						|
 | 
						|
        foreach ($this->pivotValues as $value) {
 | 
						|
            $record[$value['column']] = $value['value'];
 | 
						|
        }
 | 
						|
 | 
						|
        return $record;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the creation and update timestamps on an attach record.
 | 
						|
     *
 | 
						|
     * @param  array  $record
 | 
						|
     * @param  bool  $exists
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function addTimestampsToAttachment(array $record, $exists = false)
 | 
						|
    {
 | 
						|
        $fresh = $this->parent->freshTimestamp();
 | 
						|
 | 
						|
        if ($this->using) {
 | 
						|
            $pivotModel = new $this->using;
 | 
						|
 | 
						|
            $fresh = $fresh->format($pivotModel->getDateFormat());
 | 
						|
        }
 | 
						|
 | 
						|
        if (! $exists && $this->hasPivotColumn($this->createdAt())) {
 | 
						|
            $record[$this->createdAt()] = $fresh;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($this->hasPivotColumn($this->updatedAt())) {
 | 
						|
            $record[$this->updatedAt()] = $fresh;
 | 
						|
        }
 | 
						|
 | 
						|
        return $record;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Determine whether the given column is defined as a pivot column.
 | 
						|
     *
 | 
						|
     * @param  string  $column
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function hasPivotColumn($column)
 | 
						|
    {
 | 
						|
        return in_array($column, $this->pivotColumns);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Detach models from the relationship.
 | 
						|
     *
 | 
						|
     * @param  mixed  $ids
 | 
						|
     * @param  bool  $touch
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    public function detach($ids = null, $touch = true)
 | 
						|
    {
 | 
						|
        if ($this->using &&
 | 
						|
            ! empty($ids) &&
 | 
						|
            empty($this->pivotWheres) &&
 | 
						|
            empty($this->pivotWhereIns) &&
 | 
						|
            empty($this->pivotWhereNulls)) {
 | 
						|
            $results = $this->detachUsingCustomClass($ids);
 | 
						|
        } else {
 | 
						|
            $query = $this->newPivotQuery();
 | 
						|
 | 
						|
            // If associated IDs were passed to the method we will only delete those
 | 
						|
            // associations, otherwise all of the association ties will be broken.
 | 
						|
            // We'll return the numbers of affected rows when we do the deletes.
 | 
						|
            if (! is_null($ids)) {
 | 
						|
                $ids = $this->parseIds($ids);
 | 
						|
 | 
						|
                if (empty($ids)) {
 | 
						|
                    return 0;
 | 
						|
                }
 | 
						|
 | 
						|
                $query->whereIn($this->relatedPivotKey, (array) $ids);
 | 
						|
            }
 | 
						|
 | 
						|
            // Once we have all of the conditions set on the statement, we are ready
 | 
						|
            // to run the delete on the pivot table. Then, if the touch parameter
 | 
						|
            // is true, we will go ahead and touch all related models to sync.
 | 
						|
            $results = $query->delete();
 | 
						|
        }
 | 
						|
 | 
						|
        if ($touch) {
 | 
						|
            $this->touchIfTouching();
 | 
						|
        }
 | 
						|
 | 
						|
        return $results;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Detach models from the relationship using a custom class.
 | 
						|
     *
 | 
						|
     * @param  mixed  $ids
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    protected function detachUsingCustomClass($ids)
 | 
						|
    {
 | 
						|
        $results = 0;
 | 
						|
 | 
						|
        foreach ($this->parseIds($ids) as $id) {
 | 
						|
            $results += $this->newPivot([
 | 
						|
                $this->foreignPivotKey => $this->parent->{$this->parentKey},
 | 
						|
                $this->relatedPivotKey => $id,
 | 
						|
            ], true)->delete();
 | 
						|
        }
 | 
						|
 | 
						|
        return $results;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the pivot models that are currently attached.
 | 
						|
     *
 | 
						|
     * @return \Illuminate\Support\Collection
 | 
						|
     */
 | 
						|
    protected function getCurrentlyAttachedPivots()
 | 
						|
    {
 | 
						|
        return $this->newPivotQuery()->get()->map(function ($record) {
 | 
						|
            $class = $this->using ? $this->using : Pivot::class;
 | 
						|
 | 
						|
            $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true);
 | 
						|
 | 
						|
            return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey);
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a new pivot model instance.
 | 
						|
     *
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @param  bool  $exists
 | 
						|
     * @return \Illuminate\Database\Eloquent\Relations\Pivot
 | 
						|
     */
 | 
						|
    public function newPivot(array $attributes = [], $exists = false)
 | 
						|
    {
 | 
						|
        $pivot = $this->related->newPivot(
 | 
						|
            $this->parent, $attributes, $this->table, $exists, $this->using
 | 
						|
        );
 | 
						|
 | 
						|
        return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a new existing pivot model instance.
 | 
						|
     *
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @return \Illuminate\Database\Eloquent\Relations\Pivot
 | 
						|
     */
 | 
						|
    public function newExistingPivot(array $attributes = [])
 | 
						|
    {
 | 
						|
        return $this->newPivot($attributes, true);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get a new plain query builder for the pivot table.
 | 
						|
     *
 | 
						|
     * @return \Illuminate\Database\Query\Builder
 | 
						|
     */
 | 
						|
    public function newPivotStatement()
 | 
						|
    {
 | 
						|
        return $this->query->getQuery()->newQuery()->from($this->table);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get a new pivot statement for a given "other" ID.
 | 
						|
     *
 | 
						|
     * @param  mixed  $id
 | 
						|
     * @return \Illuminate\Database\Query\Builder
 | 
						|
     */
 | 
						|
    public function newPivotStatementForId($id)
 | 
						|
    {
 | 
						|
        return $this->newPivotQuery()->whereIn($this->relatedPivotKey, $this->parseIds($id));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a new query builder for the pivot table.
 | 
						|
     *
 | 
						|
     * @return \Illuminate\Database\Query\Builder
 | 
						|
     */
 | 
						|
    public function newPivotQuery()
 | 
						|
    {
 | 
						|
        $query = $this->newPivotStatement();
 | 
						|
 | 
						|
        foreach ($this->pivotWheres as $arguments) {
 | 
						|
            $query->where(...$arguments);
 | 
						|
        }
 | 
						|
 | 
						|
        foreach ($this->pivotWhereIns as $arguments) {
 | 
						|
            $query->whereIn(...$arguments);
 | 
						|
        }
 | 
						|
 | 
						|
        foreach ($this->pivotWhereNulls as $arguments) {
 | 
						|
            $query->whereNull(...$arguments);
 | 
						|
        }
 | 
						|
 | 
						|
        return $query->where($this->foreignPivotKey, $this->parent->{$this->parentKey});
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the columns on the pivot table to retrieve.
 | 
						|
     *
 | 
						|
     * @param  array|mixed  $columns
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    public function withPivot($columns)
 | 
						|
    {
 | 
						|
        $this->pivotColumns = array_merge(
 | 
						|
            $this->pivotColumns, is_array($columns) ? $columns : func_get_args()
 | 
						|
        );
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get all of the IDs from the given mixed value.
 | 
						|
     *
 | 
						|
     * @param  mixed  $value
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function parseIds($value)
 | 
						|
    {
 | 
						|
        if ($value instanceof Model) {
 | 
						|
            return [$value->{$this->relatedKey}];
 | 
						|
        }
 | 
						|
 | 
						|
        if ($value instanceof Collection) {
 | 
						|
            return $value->pluck($this->relatedKey)->all();
 | 
						|
        }
 | 
						|
 | 
						|
        if ($value instanceof BaseCollection) {
 | 
						|
            return $value->toArray();
 | 
						|
        }
 | 
						|
 | 
						|
        return (array) $value;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the ID from the given mixed value.
 | 
						|
     *
 | 
						|
     * @param  mixed  $value
 | 
						|
     * @return mixed
 | 
						|
     */
 | 
						|
    protected function parseId($value)
 | 
						|
    {
 | 
						|
        return $value instanceof Model ? $value->{$this->relatedKey} : $value;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Cast the given keys to integers if they are numeric and string otherwise.
 | 
						|
     *
 | 
						|
     * @param  array  $keys
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function castKeys(array $keys)
 | 
						|
    {
 | 
						|
        return array_map(function ($v) {
 | 
						|
            return $this->castKey($v);
 | 
						|
        }, $keys);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Cast the given key to convert to primary key type.
 | 
						|
     *
 | 
						|
     * @param  mixed  $key
 | 
						|
     * @return mixed
 | 
						|
     */
 | 
						|
    protected function castKey($key)
 | 
						|
    {
 | 
						|
        return $this->getTypeSwapValue(
 | 
						|
            $this->related->getKeyType(),
 | 
						|
            $key
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Cast the given pivot attributes.
 | 
						|
     *
 | 
						|
     * @param  array  $attributes
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function castAttributes($attributes)
 | 
						|
    {
 | 
						|
        return $this->using
 | 
						|
                    ? $this->newPivot()->fill($attributes)->getAttributes()
 | 
						|
                    : $attributes;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Converts a given value to a given type value.
 | 
						|
     *
 | 
						|
     * @param  string  $type
 | 
						|
     * @param  mixed  $value
 | 
						|
     * @return mixed
 | 
						|
     */
 | 
						|
    protected function getTypeSwapValue($type, $value)
 | 
						|
    {
 | 
						|
        switch (strtolower($type)) {
 | 
						|
            case 'int':
 | 
						|
            case 'integer':
 | 
						|
                return (int) $value;
 | 
						|
            case 'real':
 | 
						|
            case 'float':
 | 
						|
            case 'double':
 | 
						|
                return (float) $value;
 | 
						|
            case 'string':
 | 
						|
                return (string) $value;
 | 
						|
            default:
 | 
						|
                return $value;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |