// 2016-09-23
/**
* Format the sync list so that it is keyed by ID.
*
* @param array $records
* @return array
*/
protected function formatSyncList(array $records)
{//format the sync list so that it is keyed b ID.
$results = [];// set return values
foreach ($records as $id => $attributes) {// loop this records
if (! is_array($attributes)) {// get ID and attributes
list($id, $attributes) = [$attributes, []];
}// set list
$results[$id] = $attributes;
}// //set the result by id throw the attributes
return $results;
}// return results
/**
* Attach all of the IDs that aren't in the current array.
*
* @param array $records
* @param array $current
* @param bool $touch
* @return array
*/
protected function attachNew(array $records, array $current, $touch = true)
{// Attach all of the IDs that aren't in the current array.
$changes = ['attached' => [], 'updated' => []];//set the changes
foreach ($records as $id => $attributes) {// loop the records
// 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)) {// if this id not in the pivot group,just insert it.
$this->attach($id, $attributes, $touch);
$changes['attached'][] = is_numeric($id) ? (int) $id : (string) $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'][] = is_numeric($id) ? (int) $id : (string) $id;
}//we return them back out to the consumer.
}
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)
{// Update an existing pivot record on the table
if (in_array($this->updatedAt(), $this->pivotColumns)) {
$attributes = $this->setTimestampsOnAttach($attributes, true);
}// in_array($this->updateAt)
// set the attribute
$updated = $this->newPivotStatementForId($id)->update($attributes);
// get this updated
if ($touch) {
$this->touchIfTouching();
}// if need touch
return $updated;
}//return this result
/**
* 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 ($id instanceof Model) {
$id = $id->getKey();
}// case 1
if ($id instanceof Collection) {
$id = $id->modelKeys();
}// case 2
$query = $this->newPivotStatement();
// get the query
$query->insert($this->createAttachRecords((array) $id, $attributes));
// insert the data
if ($touch) {
$this->touchIfTouching();
}// touch something
}// first to attach
/**
* Create an array of records to insert into the pivot table.
*
* @param array $ids
* @param array $attributes
* @return array
*/
protected function createAttachRecords($ids, array $attributes)
{//Create an array of records to insert into the pivot table.
$records = [];// records
$timed = ($this->hasPivotColumn($this->createdAt()) ||
$this->hasPivotColumn($this->updatedAt()));
// set timed
// To create the p_w_upload 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->attacher($key, $value, $attributes, $timed);
}// get records by id and other relation columns
return $records;
}// return this records
/**
* Create a full p_w_upload record payload.
*
* @param int $key
* @param mixed $value
* @param array $attributes
* @param bool $timed
* @return array
*/
protected function attacher($key, $value, $attributes, $timed)
{//Create a full p_w_upload record payload
list($id, $extra) = $this->getAttachId($key, $value, $attributes);// list many return
// To create the p_w_upload 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.
$record = $this->createAttachRecord($id, $timed);// id is a key about every thing
return array_merge($record, $extra);
}//return this array_merge.
/**
* Get the attach record ID and extra attributes.
*
* @param mixed $key
* @param mixed $value
* @param array $attributes
* @return array
*/
protected function getAttachId($key, $value, array $attributes)
{//Get the attach record ID and extra attributes.
if (is_array($value)) {
return [$key, array_merge($value, $attributes)];
}// a strange thing
return [$value, $attributes];
}// return this default
/**
* Create a new pivot p_w_upload record.
*
* @param int $id
* @param bool $timed
* @return array
*/
protected function createAttachRecord($id, $timed)
{//Create a new pivot p_w_upload record
$record[$this->foreignKey] = $this->parent->getKey();// record the key
$record[$this->otherKey] = $id;//record the other key
// 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->setTimestampsOnAttach($record);
}// if you need to update this timestamps,just use parents method
return $record;
}//return record
/**
* Set the creation and update timestamps on an attach record.
*
* @param array $record
* @param bool $exists
* @return array
*/
protected function setTimestampsOnAttach(array $record, $exists = false)
{// this function just try to use father method to set about timestamps
$fresh = $this->parent->freshTimestamp();// get this function return
if (! $exists && $this->hasPivotColumn($this->createdAt())) {
$record[$this->createdAt()] = $fresh;
}// check some condition
if ($this->hasPivotColumn($this->updatedAt())) {
$record[$this->updatedAt()] = $fresh;
}// ok
return $record;
}//return this record
/**
* Detach models from the relationship.
*
* @param int|array $ids
* @param bool $touch
* @return int
*/
public function detach($ids = [], $touch = true)
{// detach models from the relationship
if ($ids instanceof Model) {
$ids = (array) $ids->getKey();// ids = (array) -> ids-> getKey
}// ids instanceof Model
$query = $this->newPivotQuery();//get a new query
// 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.
$ids = (array) $ids;// first to set the ids
if (count($ids) > 0) {
$query->whereIn($this->otherKey, (array) $ids);
}// count the query
// 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();//Once we have all of the conditions on the statement
//are ready to run the delete on the pivot table.
if ($touch) {
$this->touchIfTouching();
}
return $results;
}//just return this results
/**
* If we're touching the parent model, touch.
*
* @return void
*/
public function touchIfTouching()
{
if ($this->touchingParent()) {
$this->getParent()->touch();
}
if ($this->getParent()->touches($this->relationName)) {
$this->touch();
}
}//If we're touching the parent model,touch.
/**
* Determine if we should touch the parent on sync.
*
* @return bool
*/
protected function touchingParent()
{
return $this->getRelated()->touches($this->guessInverseRelation());
}//Determine if we should touch the parent on sync.
/**
* Attempt to guess the name of the inverse of the relation.
*
* @return string
*/
protected function guessInverseRelation()
{
return Str::camel(Str::plural(class_basename($this->getParent())));
}//Attempt to guess the name of the inverse of the relation
/**
* Create a new query builder for the pivot table.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function newPivotQuery()
{//Create a new query builder for the pivot table
$query = $this->newPivotStatement();
foreach ($this->pivotWheres as $whereArgs) {
call_user_func_array([$query, 'where'], $whereArgs);
}
return $query->where($this->foreignKey, $this->parent->getKey());
}// just a wrap function
/**
* 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 plain query builder for the pivot 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()->where($this->otherKey, $id);
}//Get a new pivot statement for a given "other" ID.
/**
* 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);
return $pivot->setPivotKeys($this->foreignKey, $this->otherKey);
}//Create a new pivot model instance.
// return set Pivot Keys
/**
* 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);
}//Create a new existing pivot model instance.
/**
* Set the columns on the pivot table to retrieve.
*
* @param array|mixed $columns
* @return $this
*/
public function withPivot($columns)
{
$columns = is_array($columns) ? $columns : func_get_args();// set this columns.
$this->pivotColumns = array_merge($this->pivotColumns, $columns);// pivot array_merge
return $this;
}// Set the columns on the pivot table to retrieve.
/**
* Specify that the pivot table has creation and update timestamps.
*
* @param mixed $createdAt
* @param mixed $updatedAt
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function withTimestamps($createdAt = null, $updatedAt = null)
{
$this->pivotCreatedAt = $createdAt;// set user
$this->pivotUpdatedAt = $updatedAt;// set user
return $this->withPivot($this->createdAt(), $this->updatedAt());
}// Specify that the pivot table has creation and update timestamps
/**
* Get the name of the "created at" column.
*
* @return string
*/
public function createdAt()
{
return $this->pivotCreatedAt ?: $this->parent->getCreatedAtColumn();
}// Get the name of the "created at" column
/**
* Get the name of the "updated at" column.
*
* @return string
*/
public function updatedAt()
{
return $this->pivotUpdatedAt ?: $this->parent->getUpdatedAtColumn();
}// pivot
/**
* Get the related model's updated at column name.
*
* @return string
*/
public function getRelatedFreshUpdate()
{
return [$this->related->getUpdatedAtColumn() => $this->related->freshTimestamp()];
}// just return
/**
* Get the key for comparing against the parent key in "has" query.
*
* @return string
*/
public function getHasCompareKey()
{
return $this->getForeignKey();
}//return
/**
* Get the fully qualified foreign key for the relation.
*
* @return string
*/
public function getForeignKey()
{
return $this->table.'.'.$this->foreignKey;
}//return
/**
* Get the fully qualified "other key" for the relation.
*
* @return string
*/
public function getOtherKey()
{
return $this->table.'.'.$this->otherKey;
}//return
/**
* Get the intermediate table for the relationship.
*
* @return string
*/
public function getTable()
{
return $this->table;
}//return
/**
* Get the relationship name for the relationship.
*
* @return string
*/
public function getRelationName()
{
return $this->relationName;
}//return
}