getIntermediateTables()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Staudenmeir\EloquentHasManyDeep\Eloquent\Relations\Traits;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Database\Eloquent\Relations\Pivot;
7
use Illuminate\Support\Str;
8
9
trait RetrievesIntermediateTables
10
{
11
    /**
12
     * The intermediate tables to retrieve.
13
     *
14
     * @var array
15
     */
16
    protected $intermediateTables = [];
17
18
    /**
19
     * Set the columns on an intermediate table to retrieve.
20
     *
21
     * @param string $class
22
     * @param array $columns
23
     * @param string|null $accessor
24
     * @return $this
25
     */
26
    public function withIntermediate($class, array $columns = ['*'], $accessor = null)
27
    {
28
        /** @var \Illuminate\Database\Eloquent\Model $instance */
29
        $instance = new $class();
30
31
        $accessor = $accessor ?: Str::snake(class_basename($class));
32
33
        return $this->withPivot($instance->getTable(), $columns, $class, $accessor);
34
    }
35
36
    /**
37
     * Set the columns on a pivot table to retrieve.
38
     *
39
     * @param string $table
40
     * @param array $columns
41
     * @param string $class
42
     * @param string|null $accessor
43
     * @param callable|null $postProcessor
44
     * @return $this
45
     */
46
    public function withPivot(
47
        $table,
48
        array $columns = ['*'],
49
        $class = Pivot::class,
50
        $accessor = null,
51
        ?callable $postProcessor = null
52
    ) {
53
        if ($columns === ['*']) {
54
            /** @var \Illuminate\Database\Connection $connection */
55
            $connection = $this->query->getConnection();
56
57
            $columns = $connection->getSchemaBuilder()->getColumnListing($table);
58
        }
59
60
        $accessor = $accessor ?: $table;
61
62
        if (isset($this->intermediateTables[$accessor])) {
63
            $columns = array_merge($columns, $this->intermediateTables[$accessor]['columns']);
64
        }
65
66
        $this->intermediateTables[$accessor] = compact('table', 'columns', 'class', 'postProcessor');
67
68
        return $this;
69
    }
70
71
    /**
72
     * Get the intermediate columns for the relation.
73
     *
74
     * @return array
75
     */
76
    protected function intermediateColumns()
77
    {
78
        $columns = [];
79
80
        foreach ($this->intermediateTables as $accessor => $intermediateTable) {
81
            $prefix = $this->prefix($accessor);
82
83
            foreach ($intermediateTable['columns'] as $column) {
84
                $columns[] = $intermediateTable['table'].'.'.$column.' as '.$prefix.$column;
85
            }
86
        }
87
88
        return array_unique($columns);
89
    }
90
91
    /**
92
     * Hydrate the intermediate table relationships on the models.
93
     *
94
     * @param array $models
95
     * @return void
96
     */
97
    protected function hydrateIntermediateRelations(array $models)
98
    {
99
        $intermediateTables = $this->intermediateTables;
100
101
        ksort($intermediateTables);
102
103
        foreach ($intermediateTables as $accessor => $intermediateTable) {
104
            $prefix = $this->prefix($accessor);
105
106
            if (str_contains($accessor, '.')) {
107
                [$path, $key] = preg_split('/\.(?=[^.]*$)/', $accessor);
108
            } else {
109
                [$path, $key] = [null, $accessor];
110
            }
111
112
            foreach ($models as $model) {
113
                $relation = $this->intermediateRelation($model, $intermediateTable, $prefix);
114
115
                data_get($model, $path)->setRelation($key, $relation);
116
            }
117
        }
118
    }
119
120
    /**
121
     * Get the intermediate relationship from the query.
122
     *
123
     * @param \Illuminate\Database\Eloquent\Model $model
124
     * @param array $intermediateTable
125
     * @param string $prefix
126
     * @return \Illuminate\Database\Eloquent\Model
127
     */
128
    protected function intermediateRelation(Model $model, array $intermediateTable, $prefix)
129
    {
130
        $attributes = $this->intermediateAttributes($model, $prefix);
131
132
        if ($intermediateTable['postProcessor']) {
133
            $attributes = $intermediateTable['postProcessor']($model, $attributes);
134
        }
135
136
        $class = $intermediateTable['class'];
137
138
        if ($class === Pivot::class) {
139
            return $class::fromAttributes($model, $attributes, $intermediateTable['table'], true);
140
        }
141
142
        if (is_subclass_of($class, Pivot::class)) {
143
            return $class::fromRawAttributes($model, $attributes, $intermediateTable['table'], true);
144
        }
145
146
        /** @var \Illuminate\Database\Eloquent\Model $instance */
147
        $instance = new $class();
148
149
        return $instance->newFromBuilder($attributes);
150
    }
151
152
    /**
153
     * Get the intermediate attributes from a model.
154
     *
155
     * @param \Illuminate\Database\Eloquent\Model $model
156
     * @param string $prefix
157
     * @return array
158
     */
159
    protected function intermediateAttributes(Model $model, $prefix)
160
    {
161
        $attributes = [];
162
163
        foreach ($model->getAttributes() as $key => $value) {
164
            if (strpos($key, $prefix) === 0) {
165
                $attributes[substr($key, strlen($prefix))] = $value;
166
167
                unset($model->$key);
168
            }
169
        }
170
171
        return $attributes;
172
    }
173
174
    /**
175
     * Get the intermediate column alias prefix.
176
     *
177
     * @param string $accessor
178
     * @return string
179
     */
180
    protected function prefix($accessor)
181
    {
182
        return '__'.$accessor.'__';
183
    }
184
185
    /**
186
     * Get the intermediate tables.
187
     *
188
     * @return array
189
     */
190
    public function getIntermediateTables(): array
191
    {
192
        return $this->intermediateTables;
193
    }
194
}
195