Skip to content

Commit

Permalink
Allow has/morph one/many relationships to specify the inverse side of…
Browse files Browse the repository at this point in the history
… the relation
  • Loading branch information
sileence committed Jul 13, 2017
1 parent 4d81d6f commit 9951ce7
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 13 deletions.
4 changes: 3 additions & 1 deletion src/Illuminate/Database/Eloquent/Relations/HasMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class HasMany extends HasOneOrMany
*/
public function getResults()
{
return $this->query->get();
return tap($this->query->get(), function ($results) {
$this->setInverseRelation($results);
});
}

/**
Expand Down
16 changes: 12 additions & 4 deletions src/Illuminate/Database/Eloquent/Relations/HasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ class HasOne extends HasOneOrMany
*/
public function getResults()
{
return $this->query->first() ?: $this->getDefaultFor($this->parent);
if (! $result = $this->query->first()) {
return $this->getDefaultFor($this->parent);
}

$this->setInverseRelation($result);

return $result;
}

/**
Expand Down Expand Up @@ -57,8 +63,10 @@ public function match(array $models, Collection $results, $relation)
*/
public function newRelatedInstanceFor(Model $parent)
{
return $this->related->newInstance()->setAttribute(
$this->getForeignKeyName(), $parent->{$this->localKey}
);
return tap($this->related->newInstance(), function ($model) use ($parent) {
$model->setAttribute($this->getForeignKeyName(), $parent->getAttribute($this->localKey));

$this->setInverseRelation($model, $parent);
});
}
}
59 changes: 56 additions & 3 deletions src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,45 @@ public function __construct(Builder $query, Model $parent, $foreignKey, $localKe
parent::__construct($query, $parent);
}

/**
* Assign the inverse side name of the relationship to be populated.
*
* @param string $name
* @return $this
*/
public function inversedBy($name)
{
$this->inverseSide = $name;

return $this;
}

/**
* Set the inverse side of the relationship on the given model.
*
* @param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection $models
* @param \Illuminate\Database\Eloquent\Mode|null $parent
* @return void
*/
protected function setInverseRelation($models, $parent = null)
{
if (! $this->inverseSide) {
return;
}

if (! $parent) {
$parent = $this->parent;
}

if ($models instanceof Collection) {
$models->each(function ($model) use ($parent) {
$model->setRelation($this->inverseSide, $parent);
});
} else {
$models->setRelation($this->inverseSide, $parent);
}
}

/**
* Create and return an un-saved instance of the related model.
*
Expand All @@ -56,6 +95,8 @@ public function make(array $attributes = [])
{
return tap($this->related->newInstance($attributes), function ($instance) {
$instance->setAttribute($this->getForeignKeyName(), $this->getParentKey());

$this->setInverseRelation($instance);
});
}

Expand Down Expand Up @@ -130,9 +171,11 @@ protected function matchOneOrMany(array $models, Collection $results, $relation,
// matching very convenient and easy work. Then we'll just return them.
foreach ($models as $model) {
if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) {
$model->setRelation(
$relation, $this->getRelationValue($dictionary, $key, $type)
);
$related = $this->getRelationValue($dictionary, $key, $type);

$this->setInverseRelation($related, $model);

$model->setRelation($relation, $related);
}
}

Expand Down Expand Up @@ -191,6 +234,8 @@ public function findOrNew($id, $columns = ['*'])
$instance->setAttribute($this->getForeignKeyName(), $this->getParentKey());
}

$this->setInverseRelation($instance);

return $instance;
}

Expand All @@ -209,6 +254,8 @@ public function firstOrNew(array $attributes, array $values = [])
$instance->setAttribute($this->getForeignKeyName(), $this->getParentKey());
}

$this->setInverseRelation($instance);

return $instance;
}

Expand All @@ -223,6 +270,8 @@ public function firstOrCreate(array $attributes, array $values = [])
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->create($attributes + $values);
} else {
$this->setInverseRelation($instance);
}

return $instance;
Expand Down Expand Up @@ -254,6 +303,8 @@ public function save(Model $model)
{
$model->setAttribute($this->getForeignKeyName(), $this->getParentKey());

$this->setInverseRelation($model);

return $model->save() ? $model : false;
}

Expand Down Expand Up @@ -283,6 +334,8 @@ public function create(array $attributes = [])
return tap($this->related->newInstance($attributes), function ($instance) {
$instance->setAttribute($this->getForeignKeyName(), $this->getParentKey());

$this->setInverseRelation($instance);

$instance->save();
});
}
Expand Down
4 changes: 3 additions & 1 deletion src/Illuminate/Database/Eloquent/Relations/MorphMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class MorphMany extends MorphOneOrMany
*/
public function getResults()
{
return $this->query->get();
return tap($this->query->get(), function ($result) {
$this->setInverseRelation($result);
});
}

/**
Expand Down
17 changes: 13 additions & 4 deletions src/Illuminate/Database/Eloquent/Relations/MorphOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ class MorphOne extends MorphOneOrMany
*/
public function getResults()
{
return $this->query->first() ?: $this->getDefaultFor($this->parent);
if (! $result = $this->query->first()) {
return $this->getDefaultFor($this->parent);
}

$this->setInverseRelation($result);

return $result;
}

/**
Expand Down Expand Up @@ -57,8 +63,11 @@ public function match(array $models, Collection $results, $relation)
*/
public function newRelatedInstanceFor(Model $parent)
{
return $this->related->newInstance()
->setAttribute($this->getForeignKeyName(), $parent->{$this->localKey})
->setAttribute($this->getMorphType(), $this->morphClass);
return tap($this->related->newInstance(), function ($model) use ($parent) {
$model->setAttribute($this->getForeignKeyName(), $parent->getAttribute($this->localKey))
->setAttribute($this->getMorphType(), $this->morphClass);

$this->setInverseRelation($model, $parent);
});
}
}
2 changes: 2 additions & 0 deletions src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ protected function setForeignAttributesForCreate(Model $model)
$model->{$this->getForeignKeyName()} = $this->getParentKey();

$model->{$this->getMorphType()} = $this->morphClass;

$this->setInverseRelation($model);
}

/**
Expand Down
9 changes: 9 additions & 0 deletions src/Illuminate/Database/Eloquent/Relations/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ abstract class Relation
*/
protected static $morphMap = [];

/**
* The inverse side of the relationship.
*
* @var string
*/
protected $inverseSide;

/**
* Create a new relation instance.
*
Expand Down Expand Up @@ -343,6 +350,8 @@ public function __call($method, $parameters)
return $this;
}

$this->setInverseRelation($result);

return $result;
}

Expand Down

0 comments on commit 9951ce7

Please sign in to comment.