Skip to content

Commit

Permalink
[5.7] Add AsPivot trait. (#25851)
Browse files Browse the repository at this point in the history
* Add IsPivot trait.

* Change name to "AsPivot".
  • Loading branch information
mathieutu authored and taylorotwell committed Oct 2, 2018
1 parent 47f95cf commit 27ab200
Show file tree
Hide file tree
Showing 2 changed files with 297 additions and 286 deletions.
295 changes: 295 additions & 0 deletions src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
<?php

namespace Illuminate\Database\Eloquent\Relations\Concerns;

use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

trait AsPivot
{
/**
* The parent model of the relationship.
*
* @var \Illuminate\Database\Eloquent\Model
*/
public $pivotParent;

/**
* The name of the foreign key column.
*
* @var string
*/
protected $foreignKey;

/**
* The name of the "other key" column.
*
* @var string
*/
protected $relatedKey;

/**
* Create a new pivot model instance.
*
* @param \Illuminate\Database\Eloquent\Model $parent
* @param array $attributes
* @param string $table
* @param bool $exists
* @return static
*/
public static function fromAttributes(Model $parent, $attributes, $table, $exists = false)
{
$instance = new static;

// The pivot model is a "dynamic" model since we will set the tables dynamically
// for the instance. This allows it work for any intermediate tables for the
// many to many relationship that are defined by this developer's classes.
$instance->setConnection($parent->getConnectionName())
->setTable($table)
->forceFill($attributes)
->syncOriginal();

// We store off the parent instance so we will access the timestamp column names
// for the model, since the pivot model timestamps aren't easily configurable
// from the developer's point of view. We can use the parents to get these.
$instance->pivotParent = $parent;

$instance->exists = $exists;

$instance->timestamps = $instance->hasTimestampAttributes();

return $instance;
}

/**
* Create a new pivot model from raw values returned from a query.
*
* @param \Illuminate\Database\Eloquent\Model $parent
* @param array $attributes
* @param string $table
* @param bool $exists
* @return static
*/
public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false)
{
$instance = static::fromAttributes($parent, [], $table, $exists);

$instance->setRawAttributes($attributes, true);

$instance->timestamps = $instance->hasTimestampAttributes();

return $instance;
}

/**
* Set the keys for a save update query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function setKeysForSaveQuery(Builder $query)
{
if (isset($this->attributes[$this->getKeyName()])) {
return parent::setKeysForSaveQuery($query);
}

$query->where($this->foreignKey, $this->getOriginal(
$this->foreignKey, $this->getAttribute($this->foreignKey)
));

return $query->where($this->relatedKey, $this->getOriginal(
$this->relatedKey, $this->getAttribute($this->relatedKey)
));
}

/**
* Delete the pivot model record from the database.
*
* @return int
*/
public function delete()
{
if (isset($this->attributes[$this->getKeyName()])) {
return parent::delete();
}

return $this->getDeleteQuery()->delete();
}

/**
* Get the query builder for a delete operation on the pivot.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function getDeleteQuery()
{
return $this->newQuery()->where([
$this->foreignKey => $this->getOriginal($this->foreignKey, $this->getAttribute($this->foreignKey)),
$this->relatedKey => $this->getOriginal($this->relatedKey, $this->getAttribute($this->relatedKey)),
]);
}

/**
* Get the table associated with the model.
*
* @return string
*/
public function getTable()
{
if (! isset($this->table)) {
$this->setTable(str_replace(
'\\', '', Str::snake(Str::singular(class_basename($this)))
));
}

return $this->table;
}

/**
* Get the foreign key column name.
*
* @return string
*/
public function getForeignKey()
{
return $this->foreignKey;
}

/**
* Get the "related key" column name.
*
* @return string
*/
public function getRelatedKey()
{
return $this->relatedKey;
}

/**
* Get the "related key" column name.
*
* @return string
*/
public function getOtherKey()
{
return $this->getRelatedKey();
}

/**
* Set the key names for the pivot model instance.
*
* @param string $foreignKey
* @param string $relatedKey
* @return $this
*/
public function setPivotKeys($foreignKey, $relatedKey)
{
$this->foreignKey = $foreignKey;

$this->relatedKey = $relatedKey;

return $this;
}

/**
* Determine if the pivot model has timestamp attributes.
*
* @return bool
*/
public function hasTimestampAttributes()
{
return array_key_exists($this->getCreatedAtColumn(), $this->attributes);
}

/**
* Get the name of the "created at" column.
*
* @return string
*/
public function getCreatedAtColumn()
{
return ($this->pivotParent)
? $this->pivotParent->getCreatedAtColumn()
: parent::getCreatedAtColumn();
}

/**
* Get the name of the "updated at" column.
*
* @return string
*/
public function getUpdatedAtColumn()
{
return ($this->pivotParent)
? $this->pivotParent->getUpdatedAtColumn()
: parent::getUpdatedAtColumn();
}

/**
* Get the queueable identity for the entity.
*
* @return mixed
*/
public function getQueueableId()
{
if (isset($this->attributes[$this->getKeyName()])) {
return $this->getKey();
}

return sprintf(
'%s:%s:%s:%s',
$this->foreignKey, $this->getAttribute($this->foreignKey),
$this->relatedKey, $this->getAttribute($this->relatedKey)
);
}

/**
* Get a new query to restore one or more models by their queueable IDs.
*
* @param array|int $ids
* @return \Illuminate\Database\Eloquent\Builder
*/
public function newQueryForRestoration($ids)
{
if (is_array($ids)) {
return $this->newQueryForCollectionRestoration($ids);
}

if (! Str::contains($ids, ':')) {
return parent::newQueryForRestoration($ids);
}

$segments = explode(':', $ids);

return $this->newQueryWithoutScopes()
->where($segments[0], $segments[1])
->where($segments[2], $segments[3]);
}

/**
* Get a new query to restore multiple models by their queueable IDs.
*
* @param array|int $ids
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function newQueryForCollectionRestoration(array $ids)
{
if (! Str::contains($ids[0], ':')) {
return parent::newQueryForRestoration($ids);
}

$query = $this->newQueryWithoutScopes();

foreach ($ids as $id) {
$segments = explode(':', $id);

$query->orWhere(function ($query) use ($segments) {
return $query->where($segments[0], $segments[1])
->where($segments[2], $segments[3]);
});
}

return $query;
}
}
Loading

0 comments on commit 27ab200

Please sign in to comment.