Completed
Push — master ( c56598...026f51 )
by ARCANEDEV
8s
created

DescendantsRelation::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 10
ccs 3
cts 3
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
crap 2
1
<?php namespace Arcanedev\LaravelNestedSet\Eloquent;
2
3
use Arcanedev\LaravelNestedSet\Utilities\NestedSet;
4
use Arcanedev\LaravelNestedSet\NodeTrait;
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
/**
13
 * Class     DescendantsRelation
14
 *
15
 * @package  Arcanedev\LaravelNestedSet\Eloquent
16
 * @author   ARCANEDEV <[email protected]>
17
 *
18
 * @method  static  \Arcanedev\LaravelNestedSet\Eloquent\Collection  get(array $columns = ['*'])
19
 */
20
class DescendantsRelation extends Relation
21
{
22
    /* ------------------------------------------------------------------------------------------------
23
     |  Properties
24
     | ------------------------------------------------------------------------------------------------
25
     */
26
    /**
27
     * The Eloquent query builder instance.
28
     *
29
     * @var \Arcanedev\LaravelNestedSet\Eloquent\QueryBuilder
30
     */
31
    protected $query;
32
33
    /**
34
     * The parent model instance.
35
     *
36
     * @var \Arcanedev\LaravelNestedSet\NodeTrait
37
     */
38
    protected $parent;
39
40
    /* ------------------------------------------------------------------------------------------------
41
     |  Constructor
42
     | ------------------------------------------------------------------------------------------------
43
     */
44
    /**
45
     * DescendantsRelation constructor.
46
     *
47
     * @param  \Arcanedev\LaravelNestedSet\Eloquent\QueryBuilder  $builder
48
     * @param  \Illuminate\Database\Eloquent\Model|NodeTrait      $model
49
     */
50 48
    public function __construct(QueryBuilder $builder, Model $model)
51
    {
52
        // @codeCoverageIgnoreStart
53
        if ( ! NestedSet::isNode($model)) {
54
            throw new InvalidArgumentException('Model must be node.');
55
        }
56
        // @codeCoverageIgnoreEnd
57
58 48
        parent::__construct($builder, $model);
59 48
    }
60
61
    /**
62
     * Add the constraints for a relationship query.
63
     *
64
     * @param  \Illuminate\Database\Eloquent\Builder  $query
65
     * @param  \Illuminate\Database\Eloquent\Builder  $parent
66
     * @param  array|mixed                            $columns
67
     *
68
     * @return \Illuminate\Database\Eloquent\Builder
69
     */
70 4
    public function getRelationQuery(
71
        EloquentBuilder $query,
72
        EloquentBuilder $parent,
73
        $columns = ['*']
74
    ) {
75 4
        $query->select($columns);
76
77 4
        $table = $query->getModel()->getTable();
78 4
        $hash  = $this->getRelationCountHash();
79
80 4
        $query->from("$table as $hash");
81
82 4
        $table = $this->wrap($table);
83 4
        $hash  = $this->wrap($hash);
84 4
        $lft   = $this->wrap($this->parent->getLftName());
85 4
        $rgt   = $this->wrap($this->parent->getRgtName());
86
87 4
        return $query->whereRaw("{$hash}.{$lft} between {$table}.{$lft} + 1 and {$table}.{$rgt}");
88
    }
89
90
    /**
91
     * Get a relationship join table hash.
92
     *
93
     * @return string
94
     */
95 4
    public function getRelationCountHash()
96
    {
97 4
        return 'self_'.md5(microtime(true));
98
    }
99
100
    /**
101
     * Set the base constraints on the relation query.
102
     */
103 48
    public function addConstraints()
104
    {
105 48
        if ( ! static::$constraints) {
106 8
            return;
107
        }
108
109 40
        $this->query->whereDescendantOf($this->parent);
110 40
    }
111
112
    /**
113
     * Set the constraints for an eager load of the relation.
114
     *
115
     * @param  array  $models
116
     */
117
    public function addEagerConstraints(array $models)
118
    {
119 4
        $this->query->whereNested(function (Builder $inner) use ($models) {
0 ignored issues
show
Documentation Bug introduced by
The method whereNested does not exist on object<Arcanedev\Laravel...\Eloquent\QueryBuilder>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
120
            // We will use this query in order to apply constraints to the base query builder
121 4
            $outer = $this->parent->newQuery();
122
123 4
            foreach ($models as $model) {
124 4
                $outer->setQuery($inner)->orWhereDescendantOf($model);
125 3
            }
126 4
        });
127 4
    }
128
129
    /**
130
     * Initialize the relation on a set of models.
131
     *
132
     * @param  array   $models
133
     * @param  string  $relation
134
     *
135
     * @return array
136
     */
137 4
    public function initRelation(array $models, $relation)
138
    {
139 4
        return $models;
140
    }
141
142
    /**
143
     * Match the eagerly loaded results to their parents.
144
     *
145
     * @param  array                                     $models
146
     * @param  \Illuminate\Database\Eloquent\Collection  $results
147
     * @param  string                                    $relation
148
     *
149
     * @return array
150
     */
151 4
    public function match(array $models, EloquentCollection $results, $relation)
152
    {
153 4
        foreach ($models as $model) {
154
            /** @var Model $model */
155 4
            $model->setRelation(
156 3
                $relation,
157 4
                $this->getDescendantsForModel($model, $results)
158 3
            );
159 3
        }
160
161 4
        return $models;
162
    }
163
164
    /**
165
     * Get the results of the relationship.
166
     *
167
     * @return mixed
168
     */
169 4
    public function getResults()
170
    {
171 4
        return $this->query->get();
172
    }
173
174
    /**
175
     * @param  \Illuminate\Database\Eloquent\Model       $model
176
     * @param  \Illuminate\Database\Eloquent\Collection  $results
177
     *
178
     * @return \Arcanedev\LaravelNestedSet\Eloquent\Collection
179
     */
180 4
    protected function getDescendantsForModel(Model $model, EloquentCollection $results)
181
    {
182 4
        $result = $this->related->newCollection();
183
184 4
        foreach ($results as $descendant) {
185 4
            if ($descendant->isDescendantOf($model)) {
186 4
                $result->push($descendant);
187 3
            }
188 3
        }
189
190 4
        return $result;
191
    }
192
}
193