/
OneToMany.php
186 lines (160 loc) · 4.24 KB
/
OneToMany.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<?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 Relation $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();
}
}