InteractsWithPivotRecords::decodeRecords()   A
last analyzed

Complexity

Conditions 5
Paths 8

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 8
nop 0
dl 0
loc 24
rs 9.5222
c 0
b 0
f 0
1
<?php
2
3
namespace Staudenmeir\EloquentJsonRelations\Relations;
4
5
use Illuminate\Database\Eloquent\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Collection as BaseCollection;
9
10
trait InteractsWithPivotRecords
11
{
12
    /**
13
     * Attach models to the relationship.
14
     *
15
     * @param mixed $ids
16
     * @return \Illuminate\Database\Eloquent\Model
17
     */
18
    public function attach($ids)
19
    {
20
        [$records, $others] = $this->decodeRecords();
21
22
        $records = $this->formatIds($this->parseIds($ids)) + $records;
23
24
        $this->child->{$this->path} = $this->encodeRecords($records, $others);
25
26
        return $this->child;
27
    }
28
29
    /**
30
     * Detach models from the relationship.
31
     *
32
     * @param mixed $ids
33
     * @return \Illuminate\Database\Eloquent\Model
34
     */
35
    public function detach($ids = null)
36
    {
37
        [$records, $others] = $this->decodeRecords();
38
39
        if (!is_null($ids)) {
40
            $records = array_diff_key(
41
                $records,
42
                array_flip($this->parseIds($ids))
43
            );
44
        } else {
45
            $records = [];
46
        }
47
48
        $this->child->{$this->path} = $this->encodeRecords($records, $others);
49
50
        return $this->child;
51
    }
52
53
    /**
54
     * Sync the relationship with a list of models.
55
     *
56
     * @param mixed $ids
57
     * @return \Illuminate\Database\Eloquent\Model
58
     */
59
    public function sync($ids)
60
    {
61
        [, $others] = $this->decodeRecords();
62
63
        $records = $this->formatIds($this->parseIds($ids));
64
65
        $this->child->{$this->path} = $this->encodeRecords($records, $others);
66
67
        return $this->child;
68
    }
69
70
    /**
71
     * Toggle models from the relationship.
72
     *
73
     * @param mixed $ids
74
     * @return \Illuminate\Database\Eloquent\Model
75
     */
76
    public function toggle($ids)
77
    {
78
        [$records, $others] = $this->decodeRecords();
79
80
        $ids = $this->formatIds($this->parseIds($ids));
81
82
        $records = array_diff_key(
83
            $ids + $records,
84
            array_intersect_key($records, $ids)
85
        );
86
87
        $this->child->{$this->path} = $this->encodeRecords($records, $others);
88
89
        return $this->child;
90
    }
91
92
    /**
93
     * Decode the records on the child model.
94
     *
95
     * @return array
96
     */
97
    protected function decodeRecords()
98
    {
99
        $records = [];
100
        $others = [];
101
102
        $key = $this->key ? str_replace('->', '.', $this->key) : $this->key;
103
104
        foreach ((array) $this->child->{$this->path} as $record) {
105
            if (!is_array($record)) {
106
                $records[$record] = [];
107
108
                continue;
109
            }
110
111
            $foreignKey = Arr::get($record, $key);
112
113
            if (!is_null($foreignKey)) {
114
                $records[$foreignKey] = $record;
115
            } else {
116
                $others[] = $record;
117
            }
118
        }
119
120
        return [$records, $others];
121
    }
122
123
    /**
124
     * Encode the records for the child model.
125
     *
126
     * @param array $records
127
     * @param array $others
128
     * @return array
129
     */
130
    protected function encodeRecords(array $records, array $others)
131
    {
132
        if (!$this->key) {
133
            return array_keys($records);
134
        }
135
136
        $key = str_replace('->', '.', $this->key);
137
138
        foreach ($records as $id => &$attributes) {
139
            Arr::set($attributes, $key, $id);
140
        }
141
142
        return array_merge(
143
            array_values($records),
144
            $others
145
        );
146
    }
147
148
    /**
149
     * Get all of the IDs from the given mixed value.
150
     *
151
     * @param mixed $value
152
     * @return array
153
     */
154
    protected function parseIds($value)
155
    {
156
        if ($value instanceof Model) {
157
            return [$value->{$this->ownerKey}];
158
        }
159
160
        if ($value instanceof Collection) {
161
            return $value->pluck($this->ownerKey)->all();
162
        }
163
164
        if ($value instanceof BaseCollection) {
165
            return $value->toArray();
166
        }
167
168
        return (array) $value;
169
    }
170
171
    /**
172
     * Format the parsed IDs.
173
     *
174
     * @param array $ids
175
     * @return array
176
     */
177
    protected function formatIds(array $ids)
178
    {
179
        return (new BaseCollection($ids))->mapWithKeys(function ($attributes, $id) {
0 ignored issues
show
Bug introduced by
$ids of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::__construct(). ( Ignorable by Annotation )

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

179
        return (new BaseCollection(/** @scrutinizer ignore-type */ $ids))->mapWithKeys(function ($attributes, $id) {
Loading history...
180
            if (!is_array($attributes)) {
181
                [$id, $attributes] = [$attributes, []];
182
            }
183
184
            return [$id => $attributes];
185
        })->all();
186
    }
187
}
188