Completed
Push — master ( 9bf7f5...90a8df )
by wen
12:07
created

Tree::finishSave()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 13
Ratio 100 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 13
loc 13
rs 9.2
cc 4
eloc 8
nc 3
nop 0
1
<?php
2
3
namespace Sco\Admin\Form\Elements;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
7
use InvalidArgumentException;
8
use Sco\Admin\Contracts\RepositoryInterface;
9
10
class Tree extends NamedElement
11
{
12
    protected $type = 'tree';
13
14
    protected $defaultValue = [];
15
16
    protected $rootNodeValue = '';
17
18
    protected $nodesModelParentAttribute = 'parent_id';
19
20
    protected $nodesModelLabelAttribute;
21
22
    protected $nodesModelValueAttribute;
23
24
    protected $nodes;
25
26
    public function __construct($name, $title, $nodes)
27
    {
28
        parent::__construct($name, $title);
29
30
        $this->setNodes($nodes);
31
    }
32
33
    public function getValue()
34
    {
35
        $value = $this->getValueFromModel();
36
        if (empty($value)) {
37
            return [];
38
        }
39
40
        if ($this->isNodesModel() && $this->isRelation()) {
41
            $model = $this->getNodesModel();
42
            $key   = $this->getNodesModelValueAttribute() ?: $model->getKeyName();
43
44
            return $value->pluck($key)->map(function ($item) {
45
                return (string)$item;
46
            });
47
        } else {
48
            return explode(',', $value);
49
        }
50
51
    }
52
53
    public function save()
54
    {
55
        if (!($this->isNodesModel() && $this->isRelation())) {
56
            parent::save();
57
        }
58
    }
59
60 View Code Duplication
    public function finishSave()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
61
    {
62
        if (!($this->isNodesModel() && $this->isRelation())) {
63
            return;
64
        }
65
        $attribute = $this->getName();
66
        $values    = $this->getValueFromRequest();
67
68
        $relation = $this->getModel()->{$attribute}();
69
        if ($relation instanceof BelongsToMany) {
70
            $relation->sync($values);
71
        }
72
    }
73
74
    protected function isNodesModel()
75
    {
76
        return is_string($this->nodes) || $this->nodes instanceof Model;
77
    }
78
79
    protected function isRelation()
80
    {
81
        return method_exists($this->getModel(), $this->getName());
82
    }
83
84
    public function getNodes()
85
    {
86 View Code Duplication
        if ($this->nodes instanceof \Closure) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
87
            $nodes = ($this->nodes)();
88
        } elseif (is_string($this->nodes) || $this->nodes instanceof Model) {
89
            $nodes = $this->setNodesFromModel();
90
        } elseif (is_array($this->nodes)) {
91
            $nodes = $this->nodes;
92
        } else {
93
            throw new InvalidArgumentException(
94
                "The form tree element's nodes must be return array"
95
            );
96
        }
97
98
        return $nodes;
99
    }
100
101
    /**
102
     * @param $nodes
103
     * @param $parentId
104
     *
105
     * @return \Illuminate\Support\Collection
106
     */
107
    public function getNodesTree($nodes, $parentId)
108
    {
109
        return collect($nodes)->filter(function ($value) use ($parentId) {
110
            if (isset($value['parent_id'])) {
111
                if ($value['parent_id'] == $parentId) {
112
                    return true;
113
                }
114
                return false;
115
            }
116
            return true;
117
        })->mapWithKeys(function ($value, $key) use ($nodes) {
118
            $data = [
119
                'id'    => (string)$value['id'],
120
                'label' => $value['label'],
121
            ];
122
123
            if (isset($value['parent_id'])) {
124
                $children = $this->getNodesTree($nodes, $value['id']);
125
                if ($children->isNotEmpty()) {
126
                    $data['children'] = $children;
127
                }
128
            }
129
130
            return [
131
                $key => $data,
132
            ];
133
        })->values();
134
    }
135
136
    public function setNodes($nodes)
137
    {
138
        $this->nodes = $nodes;
139
140
        return $this;
141
    }
142
143
    /**
144
     * @return array
145
     */
146
    protected function setNodesFromModel()
147
    {
148
        if (is_null($this->getNodesModelLabelAttribute())) {
149
            throw new InvalidArgumentException(
150
                sprintf(
151
                    "Form %s element's nodes must be set model label attribute",
152
                    $this->getType()
153
                )
154
            );
155
        }
156
157
        $model = $this->getNodesModel();
158
159
        $repository = app(RepositoryInterface::class);
160
        $repository->setModel($model);
161
162
        $results = $repository->getQuery()->get();
163
164
        $key = $this->getNodesModelValueAttribute() ?: $model->getKeyName();
165
166
        return $results->mapWithKeys(function ($item, $ikey) use ($key) {
167
            $data = [
168
                'id'    => $item[$key],
169
                'label' => $item[$this->getNodesModelLabelAttribute()],
170
            ];
171
            if (isset($item[$this->getNodesModelParentAttribute()])) {
172
                $data['parent_id'] = $item[$this->getNodesModelParentAttribute()];
173
            }
174
175
            return [
176
                $ikey => $data,
177
            ];
178
        });
179
    }
180
181
    /**
182
     * @return Model
183
     */
184 View Code Duplication
    protected function getNodesModel()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
185
    {
186
        $model = $this->nodes;
187
188
        if (is_string($model)) {
189
            $model = app($model);
190
        }
191
192
        if (!($model instanceof Model)) {
193
            throw new InvalidArgumentException(
194
                sprintf(
195
                    "Form tree element's nodes class must be instanced of '%s'.",
196
                    Model::class
197
                )
198
            );
199
        }
200
201
        return $model;
202
    }
203
204
    public function getNodesModelLabelAttribute()
205
    {
206
        return $this->nodesModelLabelAttribute;
207
    }
208
209
    public function setNodesModelLabelAttribute($value)
210
    {
211
        $this->nodesModelLabelAttribute = $value;
212
213
        return $this;
214
    }
215
216
    public function getNodesModelValueAttribute()
217
    {
218
        return $this->nodesModelValueAttribute;
219
    }
220
221
    public function setNodesModelValueAttribute($value)
222
    {
223
        $this->nodesModelValueAttribute = $value;
224
225
        return $this;
226
    }
227
228
    public function getNodesModelParentAttribute()
229
    {
230
        return $this->nodesModelParentAttribute;
231
    }
232
233
    public function setNodesModelParentAttribute($value)
234
    {
235
        $this->nodesModelParentAttribute = $value;
236
237
        return $this;
238
    }
239
240
    public function getRootNodeValue()
241
    {
242
        return $this->rootNodeValue;
243
    }
244
245
    public function setRootNodeValue($value)
246
    {
247
        $this->rootNodeValue = $value;
248
249
        return $this;
250
    }
251
252
    public function toArray()
253
    {
254
        return parent::toArray() + [
255
                'nodes' => $this->getNodesTree(
256
                    $this->getNodes(),
257
                    $this->getRootNodeValue()
258
                ),
259
            ];
260
    }
261
}
262