blob: d0a407ccd81d5ea25600e67de66823ca859318e9 [file] [log] [blame]
<?php
namespace LdapRecord\Models\Relations;
use LdapRecord\Models\Model;
use LdapRecord\Query\Collection;
use LdapRecord\Query\Model\Builder;
abstract class OneToMany extends Relation
{
/**
* The relation to merge results with.
*
* @var OneToMany|null
*/
protected $with;
/**
* The name of the relationship.
*
* @var string
*/
protected $relationName;
/**
* Whether to include recursive results.
*
* @var bool
*/
protected $recursive = false;
/**
* Constructor.
*
* @param Builder $query
* @param Model $parent
* @param string $related
* @param string $relationKey
* @param string $foreignKey
* @param string $relationName
*/
public function __construct(Builder $query, Model $parent, $related, $relationKey, $foreignKey, $relationName)
{
$this->relationName = $relationName;
parent::__construct($query, $parent, $related, $relationKey, $foreignKey);
}
/**
* Set the relation to load with its parent.
*
* @param OneToMany $relation
*
* @return $this
*/
public function with(Relation $relation)
{
$this->with = $relation;
return $this;
}
/**
* Whether to include recursive results.
*
* @param bool $enable
*
* @return $this
*/
public function recursive($enable = true)
{
$this->recursive = $enable;
return $this;
}
/**
* Get the immediate relationships results.
*
* @return Collection
*/
abstract public function getRelationResults();
/**
* Get the results of the relationship.
*
* @return Collection
*/
public function getResults()
{
$results = $this->recursive
? $this->getRecursiveResults()
: $this->getRelationResults();
return $results->merge(
$this->getMergingRelationResults()
);
}
/**
* Execute the callback excluding the merged query result.
*
* @param callable $callback
*
* @return mixed
*/
protected function onceWithoutMerging($callback)
{
$merging = $this->with;
$this->with = null;
$result = $callback();
$this->with = $merging;
return $result;
}
/**
* Get the relation name.
*
* @return string
*/
public function getRelationName()
{
return $this->relationName;
}
/**
* Get the results of the merging 'with' relation.
*
* @return Collection
*/
protected function getMergingRelationResults()
{
return $this->with
? $this->with->recursive($this->recursive)->get()
: $this->parent->newCollection();
}
/**
* Get the results for the models relation recursively.
*
* @param string[] $loaded The distinguished names of models already loaded
*
* @return Collection
*/
protected function getRecursiveResults(array $loaded = [])
{
$results = $this->getRelationResults()->reject(function (Model $model) use ($loaded) {
// Here we will exclude the models that we have already
// loaded the recursive results for so we don't run
// into issues with circular relations in LDAP.
return in_array($model->getDn(), $loaded);
});
foreach ($results as $model) {
$loaded[] = $model->getDn();
// Finally, we will fetch the related models relations,
// passing along our loaded models, to ensure we do
// not attempt fetching already loaded relations.
$results = $results->merge(
$this->getRecursiveRelationResults($model, $loaded)
);
}
return $results;
}
/**
* Get the recursive relation results for given model.
*
* @param Model $model
* @param array $loaded
*
* @return Collection
*/
protected function getRecursiveRelationResults(Model $model, array $loaded)
{
return method_exists($model, $this->relationName)
? $model->{$this->relationName}()->getRecursiveResults($loaded)
: $model->newCollection();
}
}