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