Skip to content

Commit

Permalink
Support different database connections
Browse files Browse the repository at this point in the history
  • Loading branch information
staudenmeir committed Feb 26, 2019
1 parent fc72b77 commit 0ccf22f
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 155 deletions.
255 changes: 108 additions & 147 deletions src/Relations/BelongsToThrough.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,47 @@
class BelongsToThrough extends Relation
{
/**
* Column alias for matching eagerly loaded models.
* The column alias for the local key on the first "through" parent model.
*
* @var string
*/
const RELATED_THROUGH_KEY = '__deep_related_through_key';
const THROUGH_KEY = 'laravel_through_key';

/**
* List of intermediate model instances.
* The "through" parent model instances.
*
* @var \Illuminate\Database\Eloquent\Model[]
*/
protected $models;
protected $throughParents;

/**
* The local key on the relationship.
* The foreign key prefix for the first "through" parent model.
*
* @var string
*/
protected $localKey;
protected $prefix;

/**
* TODO
*
* @var string
*/
private $prefix;

/**
* An array of table names and their foreign keys.
* The custom foreign keys on the relationship.
*
* @var array
*/
private $foreignKeyLookup;
protected $foreignKeyLookup;

/**
* Create a new belongs to through relationship instance.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Model $parent
* @param \Illuminate\Database\Eloquent\Model[] $models
* @param \Illuminate\Database\Eloquent\Model[] $throughParents
* @param string|null $localKey
* @param string $prefix
* @param array $foreignKeyLookup
* @return void
*/
public function __construct(Builder $query, Model $parent, array $models, $localKey = null, $prefix = '', $foreignKeyLookup = [])
public function __construct(Builder $query, Model $parent, array $throughParents, $localKey = null, $prefix = '', array $foreignKeyLookup = [])
{
$this->models = $models;
$this->localKey = $localKey ?: $parent->getKeyName();
$this->throughParents = $throughParents;
$this->prefix = $prefix;
$this->foreignKeyLookup = $foreignKeyLookup;

Expand All @@ -75,52 +67,51 @@ public function __construct(Builder $query, Model $parent, array $models, $local
*/
public function addConstraints()
{
$this->setJoins();

$this->query->select([$this->getRelated()->getTable().'.*']);
$this->query->select([$this->related->getTable().'.*']);

$this->setSoftDeletes();
$this->performJoins();

if (static::$constraints) {
$this->query->where($this->getQualifiedParentKeyName(), '=', $this->parent[$this->localKey]);
$localValue = $this->parent[$this->getFirstForeignKeyName()];

$this->query->whereNotNull($this->getQualifiedParentKeyName());
$this->query->where($this->getQualifiedFirstLocalKeyName(), '=', $localValue);
}
}

/**
* Set the required joins on the relation query.
* Set the join clauses on the query.
*
* @param \Illuminate\Database\Eloquent\Builder|null $query
* @return void
*/
protected function setJoins()
protected function performJoins(Builder $query = null)
{
$one = $this->getRelated()->getQualifiedKeyName();
$prev = $this->getForeignKey($this->getRelated());
$lastIndex = count($this->models) - 1;
$query = $query ?: $this->query;

foreach ($this->models as $index => $model) {
if ($lastIndex === $index) {
$prev = $this->prefix.$prev;
}
foreach ($this->throughParents as $i => $model) {
$table = $model->getTable();

$predecessor = $i > 0 ? $this->throughParents[$i - 1] : $this->related;

$other = $model->getTable().'.'.$prev;
$first = $table.'.'.$this->getForeignKeyName($predecessor);

$this->query->leftJoin($model->getTable(), $one, '=', $other);
$second = $predecessor->getQualifiedKeyName();

$prev = $this->getForeignKey($model);
$query->join($table, $first, '=', $second);

$one = $model->getQualifiedKeyName();
if ($this->hasSoftDeletes($model)) {
$this->query->whereNull($model->getQualifiedDeletedAtColumn());
}
}
}

/**
* Get foreign key column name for the model.
* Get the foreign key for a model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return string
*/
protected function getForeignKey(Model $model)
protected function getForeignKeyName(Model $model)
{
$table = $model->getTable();

Expand All @@ -132,25 +123,7 @@ protected function getForeignKey(Model $model)
}

/**
* Set the soft deleting constraints on the relation query.
*
* @return void
*/
protected function setSoftDeletes()
{
foreach ($this->models as $model) {
if ($model === $this->parent) {
continue;
}

if ($this->hasSoftDeletes($model)) {
$this->query->whereNull($model->getQualifiedDeletedAtColumn());
}
}
}

/**
* Determine whether the model uses Soft Deletes.
* Determine whether a model uses SoftDeletes.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return bool
Expand All @@ -169,48 +142,80 @@ public function hasSoftDeletes(Model $model)
public function addEagerConstraints(array $models)
{
$this->query->addSelect([
$this->getParent()->getQualifiedKeyName().' as '.static::RELATED_THROUGH_KEY,
$this->getQualifiedFirstLocalKeyName().' as '.static::THROUGH_KEY,
]);

$this->query->whereIn($this->getParent()->getQualifiedKeyName(), $this->getKeys($models, $this->localKey));
$keys = $this->getKeys($models, $this->getFirstForeignKeyName());

$this->query->whereIn($this->getQualifiedFirstLocalKeyName(), $keys);
}

/**
* TODO
* Initialize the relation on a set of models.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return void
* @param \Illuminate\Database\Eloquent\Model[] $models
* @param string $relation
* @return array
*/
protected function setRelationQueryConstraints(Builder $query)
public function initRelation(array $models, $relation)
{
$one = $this->getRelated()->getQualifiedKeyName();
$prev = $this->getForeignKey($this->getRelated());
$alias = null;
$lastIndex = count($this->models) - 1;
foreach ($this->models as $index => $model) {
if ($lastIndex === $index) {
$prev = $this->prefix.$prev;
}
if ($this->getParent()->getTable() === $model->getTable()) {
$alias = $model->getTable().'_'.time();
$other = $alias.'.'.$prev;
$query->leftJoin(new Expression($model->getTable().' as '.$alias), $one, '=', $other);
} else {
$other = $model->getTable().'.'.$prev;
$query->leftJoin($model->getTable(), $one, '=', $other);
foreach ($models as $model) {
$model->setRelation($relation, null);
}

return $models;
}

/**
* Match the eagerly loaded results to their parents.
*
* @param \Illuminate\Database\Eloquent\Model[] $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
$dictionary = $this->buildDictionary($results);

foreach ($models as $model) {
$key = $model[$this->getFirstForeignKeyName()];

if (isset($dictionary[$key])) {
$model->setRelation($relation, $dictionary[$key]);
}
}

$prev = $this->getForeignKey($model);
$one = $model->getQualifiedKeyName();
return $models;
}

/**
* Build model dictionary keyed by the relation's foreign key.
*
* @param \Illuminate\Database\Eloquent\Collection $results
* @return array
*/
protected function buildDictionary(Collection $results)
{
$dictionary = [];

foreach ($results as $result) {
$dictionary[$result[static::THROUGH_KEY]] = $result;

unset($result[static::THROUGH_KEY]);
}

$key = $this->parent
->newQueryWithoutScopes()
->getQuery()
->getGrammar()
->wrap($this->getQualifiedParentKeyName());
return $dictionary;
}

$query->where(new Expression($alias.'.'.$this->getParent()->getKeyName()), '=', new Expression($key));
/**
* Get the results of the relationship.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function getResults()
{
return $this->query->first();
}

/**
Expand All @@ -223,11 +228,15 @@ protected function setRelationQueryConstraints(Builder $query)
*/
public function getRelationExistenceQuery(Builder $query, Builder $parent, $columns = ['*'])
{
$query->select($columns);
$this->performJoins($query);

$foreignKey = $parent->getQuery()->from.'.'.$this->getFirstForeignKeyName();

$this->setRelationQueryConstraints($query);
$foreignKey = new Expression($query->getQuery()->getGrammar()->wrap($foreignKey));

return $query;
return $query->select($columns)->where(
$this->getQualifiedFirstLocalKeyName(), '=', $foreignKey
);
}

/**
Expand Down Expand Up @@ -256,70 +265,22 @@ public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*
}

/**
* Get the results of the relationship.
* Get the foreign key for the first "through" parent model.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function getResults()
{
return $this->query->first();
}

/**
* Initialize the relation on a set of models.
*
* @param \Illuminate\Database\Eloquent\Model[] $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, null);
}

return $models;
}

/**
* Match the eagerly loaded results to their parents.
*
* @param \Illuminate\Database\Eloquent\Model[] $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
* @return string
*/
public function match(array $models, Collection $results, $relation)
public function getFirstForeignKeyName()
{
$dictionary = $this->buildDictionary($results);

foreach ($models as $model) {
$key = $model->{$this->localKey};

if (isset($dictionary[$key])) {
$model->setRelation($relation, $dictionary[$key]);
}
}

return $models;
return $this->prefix.$this->getForeignKeyName(end($this->throughParents));
}

/**
* Build model dictionary keyed by the relation's foreign key.
* Get the qualified local key for the first "through" parent model.
*
* @param \Illuminate\Database\Eloquent\Collection $results
* @return array
* @return string
*/
protected function buildDictionary(Collection $results)
public function getQualifiedFirstLocalKeyName()
{
$dictionary = [];

foreach ($results as $result) {
$dictionary[$result->{static::RELATED_THROUGH_KEY}] = $result;

unset($result[static::RELATED_THROUGH_KEY]);
}

return $dictionary;
return end($this->throughParents)->getQualifiedKeyName();
}
}
Loading

0 comments on commit 0ccf22f

Please sign in to comment.