Passed
Push — master ( 4e5334...4eb7e1 )
by Jonas
04:13
created

Siblings   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 17
eloc 60
c 2
b 0
f 0
dl 0
loc 180
ccs 72
cts 72
cp 1
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getResults() 0 3 1
A getRelationExistenceQueryForSelfRelation() 0 28 2
A addConstraints() 0 15 4
A match() 0 21 4
A __construct() 0 5 1
A addEagerConstraints() 0 8 2
A getRelationExistenceQuery() 0 26 3
1
<?php
2
3
namespace Staudenmeir\LaravelAdjacencyList\Eloquent\Relations;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Relations\HasMany;
9
10
class Siblings extends HasMany
11
{
12
    /**
13
     * Whether to include the parent model.
14
     *
15
     * @var bool
16
     */
17
    protected $andSelf;
18
19
    /**
20
     * Create a new siblings relationship instance.
21
     *
22
     * @param \Illuminate\Database\Eloquent\Builder $query
23
     * @param \Illuminate\Database\Eloquent\Model $parent
24
     * @param string $foreignKey
25
     * @param string $localKey
26
     * @param bool $andSelf
27
     * @return void
28
     */
29 52
    public function __construct(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
30
    {
31 52
        $this->andSelf = $andSelf;
32
33 52
        parent::__construct($query, $parent, $foreignKey, $localKey);
34 52
    }
35
36
    /**
37
     * Set the base constraints on the relation query.
38
     *
39
     * @return void
40
     */
41 52
    public function addConstraints()
42
    {
43 52
        if (static::$constraints) {
44 20
            $this->query->where($this->foreignKey, '=', $this->getParentKey());
45
46 20
            if (!$this->andSelf) {
47 12
                $this->query->where(
48 12
                    $this->related->getQualifiedLocalKeyName(),
49 12
                    '<>',
50 12
                    $this->parent->{$this->parent->getLocalKeyName()}
51
                );
52
            }
53
54 20
            if (!array_key_exists($this->localKey, $this->parent->getAttributes())) {
55 4
                $this->query->whereNotNull($this->foreignKey);
56
            }
57
        }
58 52
    }
59
60
    /**
61
     * Set the constraints for an eager load of the relation.
62
     *
63
     * @param array $models
64
     * @return void
65
     */
66 16
    public function addEagerConstraints(array $models)
67
    {
68 16
        $keys = $this->getKeys($models, $this->localKey);
69
70 16
        $this->query->whereIn($this->foreignKey, $keys);
71
72 16
        if (in_array(null, $keys, true)) {
73 16
            $this->query->orWhereNull($this->foreignKey);
74
        }
75 16
    }
76
77
    /**
78
     * Match the eagerly loaded results to their parents.
79
     *
80
     * @param array $models
81
     * @param \Illuminate\Database\Eloquent\Collection $results
82
     * @param string $relation
83
     * @return array
84
     */
85 16
    public function match(array $models, Collection $results, $relation)
86
    {
87 16
        $dictionary = $this->buildDictionary($results);
88
89 16
        foreach ($models as $model) {
90 16
            $key = $model->{$this->localKey};
91
92 16
            if (isset($dictionary[$key])) {
93 16
                $value = $this->related->newCollection($dictionary[$key]);
94
95 16
                if (!$this->andSelf) {
96 8
                    $value = $value->reject(function (Model $result) use ($model) {
97 8
                        return $result->{$result->getLocalKeyName()} == $model->{$model->getLocalKeyName()};
98 8
                    })->values();
99
                }
100
101 16
                $model->setRelation($relation, $value);
102
            }
103
        }
104
105 16
        return $models;
106
    }
107
108
    /**
109
     * Get the results of the relationship.
110
     *
111
     * @return mixed
112
     */
113 20
    public function getResults()
114
    {
115 20
        return $this->query->get();
116
    }
117
118
    /**
119
     * Add the constraints for a relationship query.
120
     *
121
     * @param \Illuminate\Database\Eloquent\Builder $query
122
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
123
     * @param array|mixed $columns
124
     * @return \Illuminate\Database\Eloquent\Builder
125
     */
126 16
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
127
    {
128 16
        if ($query->getQuery()->from === $parentQuery->getQuery()->from) {
129 8
            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);
130
        }
131
132 8
        $first = $this->foreignKey;
133 8
        $second = $parentQuery->qualifyColumn($this->localKey);
134
135 8
        $query->select($columns)
136 8
            ->where(function (Builder $query) use ($first, $second) {
137 8
                $query->whereColumn($first, '=', $second)
138 8
                    ->orWhere(function (Builder $query) use ($first, $second) {
139 8
                        $query->whereNull($first)->whereNull($second);
140 8
                    });
141 8
            });
142
143 8
        if (!$this->andSelf) {
144 4
            $query->whereColumn(
145 4
                $this->related->getQualifiedLocalKeyName(),
146 4
                '<>',
147 4
                $this->parent->getQualifiedLocalKeyName()
148
            );
149
        }
150
151 8
        return $query;
152
    }
153
154
    /**
155
     * Add the constraints for a relationship query on the same table.
156
     *
157
     * @param \Illuminate\Database\Eloquent\Builder $query
158
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
159
     * @param array|mixed $columns
160
     * @return \Illuminate\Database\Eloquent\Builder
161
     */
162 8
    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
163
    {
164 8
        $table = $this->getRelationCountHash();
165
166 8
        $query->from($query->getModel()->getTable().' as '.$table);
167
168 8
        $query->getModel()->setTable($table);
169
170 8
        $first = $table.'.'.$this->getForeignKeyName();
171 8
        $second = $this->getQualifiedParentKeyName();
172
173 8
        $query->select($columns)
174 8
            ->where(function (Builder $query) use ($first, $second) {
175 8
                $query->whereColumn($first, '=', $second)
176 8
                    ->orWhere(function (Builder $query) use ($first, $second) {
177 8
                        $query->whereNull($first)->whereNull($second);
178 8
                    });
179 8
            });
180
181 8
        if (!$this->andSelf) {
182 4
            $query->whereColumn(
183 4
                $table.'.'.$this->related->getLocalKeyName(),
0 ignored issues
show
Bug introduced by
Are you sure $this->related->getLocalKeyName() of type Illuminate\Database\Eloquent\Builder|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

183
                $table.'.'./** @scrutinizer ignore-type */ $this->related->getLocalKeyName(),
Loading history...
184 4
                '<>',
185 4
                $this->parent->getQualifiedLocalKeyName()
186
            );
187
        }
188
189 8
        return $query;
190
    }
191
}
192