Completed
Pull Request — master (#2)
by ARCANEDEV
09:08
created

DescendantsRelation   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 7

Test Coverage

Coverage 74.47%

Importance

Changes 0
Metric Value
wmc 15
lcom 2
cbo 7
dl 0
loc 173
ccs 35
cts 47
cp 0.7447
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 2
A addConstraints() 0 8 2
A addEagerConstraints() 0 11 2
A initRelation() 0 4 1
A match() 0 12 2
A getResults() 0 4 1
A getDescendantsForModel() 0 12 3
A getRelationQuery() 0 19 1
A getRelationCountHash() 0 4 1
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 36
    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 36
        parent::__construct($builder, $model);
59 36
    }
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
    public function getRelationQuery(
71
        EloquentBuilder $query,
72
        EloquentBuilder $parent,
0 ignored issues
show
Unused Code introduced by
The parameter $parent is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
73
        $columns = ['*']
74
    ) {
75
        $query->select($columns);
0 ignored issues
show
Bug introduced by
The method select() does not exist on Illuminate\Database\Eloquent\Builder. Did you maybe mean createSelectWithConstraint()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
76
77
        $table = $query->getModel()->getTable();
78
        $hash  = $this->getRelationCountHash();
79
80
        $query->from("$table as $hash");
81
82
        $table = $this->wrap($table);
0 ignored issues
show
Documentation Bug introduced by
The method wrap does not exist on object<Arcanedev\Laravel...nt\DescendantsRelation>? 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...
83
        $hash  = $this->wrap($hash);
0 ignored issues
show
Documentation Bug introduced by
The method wrap does not exist on object<Arcanedev\Laravel...nt\DescendantsRelation>? 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...
84
        $lft   = $this->wrap($this->parent->getLftName());
0 ignored issues
show
Documentation Bug introduced by
The method wrap does not exist on object<Arcanedev\Laravel...nt\DescendantsRelation>? 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...
85
        $rgt   = $this->wrap($this->parent->getRgtName());
0 ignored issues
show
Documentation Bug introduced by
The method wrap does not exist on object<Arcanedev\Laravel...nt\DescendantsRelation>? 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...
86
87
        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
    public function getRelationCountHash()
96
    {
97
        return 'self_'.md5(microtime(true));
98
    }
99
100
    /**
101
     * Set the base constraints on the relation query.
102
     */
103 36
    public function addConstraints()
104
    {
105 36
        if ( ! static::$constraints) {
106 6
            return;
107
        }
108
109 30
        $this->query->whereDescendantOf($this->parent);
110 30
    }
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 3
        $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 3
            $outer = $this->parent->newQuery();
122
123 3
            foreach ($models as $model) {
124 3
                $outer->setQuery($inner)->orWhereDescendantOf($model);
125 1
            }
126 3
        });
127 3
    }
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 3
    public function initRelation(array $models, $relation)
138
    {
139 3
        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 3
    public function match(array $models, EloquentCollection $results, $relation)
152
    {
153 3
        foreach ($models as $model) {
154
            /** @var Model $model */
155 3
            $model->setRelation(
156 1
                $relation,
157 3
                $this->getDescendantsForModel($model, $results)
158 1
            );
159 1
        }
160
161 3
        return $models;
162
    }
163
164
    /**
165
     * Get the results of the relationship.
166
     *
167
     * @return mixed
168
     */
169 3
    public function getResults()
170
    {
171 3
        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 3
    protected function getDescendantsForModel(Model $model, EloquentCollection $results)
181
    {
182 3
        $result = $this->related->newCollection();
183
184 3
        foreach ($results as $descendant) {
185 3
            if ($descendant->isDescendantOf($model)) {
186 3
                $result->push($descendant);
187 1
            }
188 1
        }
189
190 3
        return $result;
191
    }
192
}
193