Issues (36)

ThirdParty/LaravelHasManyMerged/HasManyMerged.php (1 issue)

1
<?php
2
3
namespace Staudenmeir\EloquentHasManyDeep\Eloquent\Relations\ThirdParty\LaravelHasManyMerged;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Database\Query\JoinClause;
8
use Korridor\LaravelHasManyMerged\HasManyMerged as Base;
9
use Staudenmeir\EloquentHasManyDeepContracts\Interfaces\ConcatenableRelation;
10
11
/**
12
 * @copyright Based on package by Constantin Graf (korridor): https://github.com/korridor/laravel-has-many-merged
13
 */
14
class HasManyMerged extends Base implements ConcatenableRelation
15
{
16
    /**
17
     * Append the relation's through parents, foreign and local keys to a deep relationship.
18
     *
19
     * @param \Illuminate\Database\Eloquent\Model[] $through
20
     * @param array $foreignKeys
21
     * @param array $localKeys
22
     * @param int $position
23
     * @return array
24
     */
25 30
    public function appendToDeepRelationship(array $through, array $foreignKeys, array $localKeys, int $position): array
26
    {
27 30
        if ($position === 0) {
28 14
            $foreignKeys[] = function (Builder $query, Builder $parentQuery = null) {
29 10
                if ($parentQuery) {
30 2
                    $this->getRelationExistenceQuery($this->query, $parentQuery);
31
                }
32
33 10
                $query->mergeConstraintsFrom($this->query);
34 14
            };
35
36 14
            $localKeys[] = $this->localKey;
37
        } else {
38 16
            $foreignKeys[] = function (Builder $query, JoinClause $join) {
39 16
                $join->on(
40 16
                    function (JoinClause $join) {
41 16
                        foreach ($this->foreignKeys as $foreignKey) {
42 16
                            $join->orOn($foreignKey, '=', $this->getQualifiedParentKeyName());
43
                        }
44 16
                    }
45 16
                );
46 16
            };
47
48 16
            $localKeys[] = null;
49
        }
50
51 30
        return [$through, $foreignKeys, $localKeys];
52
    }
53
54
    /**
55
     * Get the custom through key for an eager load of the relation.
56
     *
57
     * @param string $alias
58
     * @return array
59
     */
60 12
    public function getThroughKeyForDeepRelationships(string $alias): array
61
    {
62 12
        $columns = [];
63
64 12
        foreach ($this->foreignKeys as $i => $foreignKey) {
65 12
            $columns[] = "$foreignKey as $alias" . ($i > 0 ? "_$i" : '');
66
        }
67
68 12
        return $columns;
69
    }
70
71
    /**
72
     * Set the constraints for an eager load of the deep relation.
73
     *
74
     * @param \Illuminate\Database\Eloquent\Builder $query
75
     * @param array $models
76
     * @return void
77
     */
78 4
    public function addEagerConstraintsToDeepRelationship(Builder $query, array $models): void
79
    {
80 4
        $this->addEagerConstraints($models);
81
82 4
        $query->mergeConstraintsFrom($this->query);
83
    }
84
85
    /**
86
     * Match the eagerly loaded results for a deep relationship to their parents.
87
     *
88
     * @param array $models
89
     * @param \Illuminate\Database\Eloquent\Collection $results
90
     * @param string $relation
91
     * @return array
92
     */
93 4
    public function matchResultsForDeepRelationship(array $models, Collection $results, string $relation): array
94
    {
95 4
        $dictionary = $this->buildDictionaryForDeepRelationship($results);
96
97 4
        foreach ($models as $model) {
98 4
            if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) {
99 4
                $model->setRelation(
100 4
                    $relation,
101 4
                    $this->getRelated()->newCollection($dictionary[$key])->unique($this->getRelated()->getKeyName())
102 4
                );
103
            }
104
        }
105
106 4
        return $models;
107
    }
108
109
    /**
110
     * Build the model dictionary for a deep relation.
111
     *
112
     * @param \Illuminate\Database\Eloquent\Collection $results
113
     * @return array
114
     */
115 4
    protected function buildDictionaryForDeepRelationship(Collection $results): array
116
    {
117 4
        $dictionary = [];
118
119 4
        $foreignKeyNames = array_map(
120 4
            fn ($i) => 'laravel_through_key' . ($i > 0 ? "_$i" : ''),
121 4
            range(0, count($this->foreignKeys) - 1)
122 4
        );
123
124 4
        foreach ($results as $result) {
125 4
            foreach ($foreignKeyNames as $foreignKeyName) {
126 4
                $foreignKeyValue = $result->{$foreignKeyName};
127 4
                if (!isset($dictionary[$foreignKeyValue])) {
128 4
                    $dictionary[$foreignKeyValue] = [];
129
                }
130
131 4
                $dictionary[$foreignKeyValue][] = $result;
132
            }
133
        }
134
135 4
        return $dictionary;
136
    }
137
138
    /**
139
     * Create a new instance of the relation from a base relation instance.
140
     *
141
     * @param \Korridor\LaravelHasManyMerged\HasManyMerged $relation
142
     * @return static
143
     */
144 30
    public static function fromBaseRelation(Base $relation): static
145
    {
146 30
        return new static(
147 30
            $relation->getQuery(),
148 30
            $relation->getParent(),
149 30
            $relation->getQualifiedForeignKeyNames(),
150 30
            (fn () => $this->localKey)->call($relation)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $this seems to be never defined.
Loading history...
151 30
        );
152
    }
153
}
154