1
+ <?php
2
+
3
+ namespace Kalnoy \Nestedset ;
4
+
5
+ use Illuminate \Database \Eloquent \Builder as EloquentBuilder ;
6
+ use Illuminate \Database \Eloquent \Collection as EloquentCollection ;
7
+ use Illuminate \Database \Eloquent \Model ;
8
+ use Illuminate \Database \Eloquent \Relations \Relation ;
9
+ use Illuminate \Database \Query \Builder ;
10
+ use InvalidArgumentException ;
11
+
12
+ class DescendantsRelation extends Relation
13
+ {
14
+ /**
15
+ * @var QueryBuilder
16
+ */
17
+ protected $ query ;
18
+
19
+ /**
20
+ * @var NodeTrait|Model
21
+ */
22
+ protected $ parent ;
23
+
24
+ /**
25
+ * DescendantsRelation constructor.
26
+ *
27
+ * @param QueryBuilder $builder
28
+ * @param Model $model
29
+ */
30
+ public function __construct (QueryBuilder $ builder , Model $ model )
31
+ {
32
+ if ( ! NestedSet::isNode ($ model )) {
33
+ throw new InvalidArgumentException ('Model must be node. ' );
34
+ }
35
+
36
+ parent ::__construct ($ builder , $ model );
37
+ }
38
+
39
+ /**
40
+ * @param EloquentBuilder $query
41
+ * @param EloquentBuilder $parent
42
+ * @param array $columns
43
+ *
44
+ * @return mixed
45
+ */
46
+ public function getRelationQuery (EloquentBuilder $ query , EloquentBuilder $ parent ,
47
+ $ columns = [ '* ' ]
48
+ ) {
49
+ $ query ->select ($ columns );
50
+
51
+ $ table = $ query ->getModel ()->getTable ();
52
+
53
+ $ query ->from ($ table .' as ' .$ hash = $ this ->getRelationCountHash ());
54
+
55
+ $ table = $ this ->wrap ($ table );
56
+ $ hash = $ this ->wrap ($ hash );
57
+ $ lft = $ this ->wrap ($ this ->parent ->getLftName ());
58
+ $ rgt = $ this ->wrap ($ this ->parent ->getRgtName ());
59
+
60
+ return $ query ->whereRaw ("{$ hash }. {$ lft } between {$ table }. {$ lft } + 1 and {$ table }. {$ rgt }" );
61
+ }
62
+
63
+ /**
64
+ * Get a relationship join table hash.
65
+ *
66
+ * @return string
67
+ */
68
+ public function getRelationCountHash ()
69
+ {
70
+ return 'self_ ' .md5 (microtime (true ));
71
+ }
72
+
73
+ /**
74
+ * Set the base constraints on the relation query.
75
+ *
76
+ * @return void
77
+ */
78
+ public function addConstraints ()
79
+ {
80
+ if ( ! static ::$ constraints ) return ;
81
+
82
+ $ this ->query ->whereDescendantOf ($ this ->parent );
83
+ }
84
+
85
+ /**
86
+ * Set the constraints for an eager load of the relation.
87
+ *
88
+ * @param array $models
89
+ *
90
+ * @return void
91
+ */
92
+ public function addEagerConstraints (array $ models )
93
+ {
94
+ $ this ->query ->whereNested (function (Builder $ inner ) use ($ models ) {
95
+ // We will use this query in order to apply constraints to the
96
+ // base query builder
97
+ $ outer = $ this ->parent ->newQuery ();
98
+
99
+ foreach ($ models as $ model ) {
100
+ $ outer ->setQuery ($ inner )->orWhereDescendantOf ($ model );
101
+ }
102
+ });
103
+ }
104
+
105
+ /**
106
+ * Initialize the relation on a set of models.
107
+ *
108
+ * @param array $models
109
+ * @param string $relation
110
+ *
111
+ * @return array
112
+ */
113
+ public function initRelation (array $ models , $ relation )
114
+ {
115
+ return $ models ;
116
+ }
117
+
118
+ /**
119
+ * Match the eagerly loaded results to their parents.
120
+ *
121
+ * @param array $models
122
+ * @param EloquentCollection $results
123
+ * @param string $relation
124
+ *
125
+ * @return array
126
+ */
127
+ public function match (array $ models , EloquentCollection $ results , $ relation )
128
+ {
129
+ foreach ($ models as $ model ) {
130
+ $ descendants = $ this ->getDescendantsForModel ($ model , $ results );
131
+
132
+ $ model ->setRelation ($ relation , $ descendants );
133
+ }
134
+
135
+ return $ models ;
136
+ }
137
+
138
+ /**
139
+ * Get the results of the relationship.
140
+ *
141
+ * @return mixed
142
+ */
143
+ public function getResults ()
144
+ {
145
+ return $ this ->query ->get ();
146
+ }
147
+
148
+ /**
149
+ * @param Model $model
150
+ * @param EloquentCollection $results
151
+ *
152
+ * @return Collection
153
+ */
154
+ protected function getDescendantsForModel (Model $ model , EloquentCollection $ results )
155
+ {
156
+ $ result = $ this ->related ->newCollection ();
157
+
158
+ foreach ($ results as $ descendant ) {
159
+ if ($ descendant ->isDescendantOf ($ model )) {
160
+ $ result ->push ($ descendant );
161
+ }
162
+ }
163
+
164
+ return $ result ;
165
+ }
166
+ }
0 commit comments