Completed
Push — master ( 4291f9...cb1f21 )
by Nekrasov
03:34
created

WidgetGroup   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 317
Duplicated Lines 6.94 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 33
c 3
b 0
f 0
lcom 1
cbo 2
dl 22
loc 317
rs 9.3999

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A display() 0 20 4
A removeById() 12 12 4
A removeByName() 10 10 4
A removeByPosition() 0 6 2
A removeAll() 0 4 1
A position() 0 6 1
A addWidget() 0 4 1
A addAsyncWidget() 0 4 1
A getPosition() 0 4 1
A setSeparator() 0 6 1
A wrap() 0 6 1
A any() 0 4 1
A isEmpty() 0 4 1
A count() 0 9 2
A addWidgetWithType() 0 18 2
A displayWidget() 0 6 2
A resetPosition() 0 4 1
A performWrap() 0 10 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Arrilot\Widgets;
4
5
use Arrilot\Widgets\Contracts\ApplicationWrapperContract;
6
use Arrilot\Widgets\Misc\ViewExpressionTrait;
7
8
class WidgetGroup
9
{
10
    use ViewExpressionTrait;
11
12
    /**
13
     * The widget group name.
14
     *
15
     * @var string
16
     */
17
    protected $name;
18
19
    /**
20
     * The application wrapper.
21
     *
22
     * @var ApplicationWrapperContract
23
     */
24
    protected $app;
25
26
    /**
27
     * The array of widgets to display in this group.
28
     *
29
     * @var array
30
     */
31
    protected $widgets = [];
32
33
    /**
34
     * The position of a widget in this group.
35
     *
36
     * @var int
37
     */
38
    protected $position = 100;
39
40
    /**
41
     * The separator to display between widgets in the group.
42
     *
43
     * @var string
44
     */
45
    protected $separator = '';
46
47
    /**
48
     * Id that is going to be issued to the next widget when it's added to the group.
49
     *
50
     * @var int
51
     */
52
    protected $nextWidgetId = 1;
53
54
    /**
55
     * A callback that defines extra markup that wraps every widget in the group.
56
     *
57
     * @var callable
58
     */
59
    protected $wrapCallback;
60
61
    /**
62
     * @param $name
63
     * @param ApplicationWrapperContract $app
64
     */
65
    public function __construct($name, ApplicationWrapperContract $app)
66
    {
67
        $this->name = $name;
68
69
        $this->app = $app;
70
    }
71
72
    /**
73
     * Display all widgets from this group in correct order.
74
     *
75
     * @return string
76
     */
77
    public function display()
78
    {
79
        ksort($this->widgets);
80
81
        $output = '';
82
        $index = 0;
83
        $count = $this->count();
84
85
        foreach ($this->widgets as $position => $widgets) {
86
            foreach ($widgets as $widget) {
87
                $output .= $this->performWrap($this->displayWidget($widget), $index, $count);
88
                $index++;
89
                if ($index !== $count) {
90
                    $output .= $this->separator;
91
                }
92
            }
93
        }
94
95
        return $this->convertToViewExpression($output);
96
    }
97
98
    /**
99
     * Remove a widget by its id.
100
     *
101
     * @param int $id
102
     */
103 View Code Duplication
    public function removeById($id)
104
    {
105
        foreach ($this->widgets as $position => $widgets) {
106
            foreach ($widgets as $i => $widget) {
107
                if ($widget['id'] === $id) {
108
                    unset($this->widgets[$position][$i]);
109
110
                    return;
111
                }
112
            }
113
        }
114
    }
115
116
    /**
117
     * Remove all widgets with $name from the group.
118
     *
119
     * @param string $name
120
     */
121 View Code Duplication
    public function removeByName($name)
122
    {
123
        foreach ($this->widgets as $position => $widgets) {
124
            foreach ($widgets as $i => $widget) {
125
                if ($widget['arguments'][0] === $name) {
126
                    unset($this->widgets[$position][$i]);
127
                }
128
            }
129
        }
130
    }
131
132
    /**
133
     * Remove all widgets from $position from the group.
134
     *
135
     * @param int|string $position
136
     */
137
    public function removeByPosition($position)
138
    {
139
        if (array_key_exists($position, $this->widgets)) {
140
            unset($this->widgets[$position]);
141
        }
142
    }
143
144
    /**
145
     * Remove all widgets from the group.
146
     */
147
    public function removeAll()
148
    {
149
        $this->widgets = [];
150
    }
151
152
    /**
153
     * Set widget position.
154
     *
155
     * @param int $position
156
     *
157
     * @return $this
158
     */
159
    public function position($position)
160
    {
161
        $this->position = $position;
162
163
        return $this;
164
    }
165
166
    /**
167
     * Add a widget to the group.
168
     */
169
    public function addWidget()
170
    {
171
        return $this->addWidgetWithType('sync', func_get_args());
172
    }
173
174
    /**
175
     * Add an async widget to the group.
176
     */
177
    public function addAsyncWidget()
178
    {
179
        return $this->addWidgetWithType('async', func_get_args());
180
    }
181
182
    /**
183
     * Getter for position.
184
     *
185
     * @return int
186
     */
187
    public function getPosition()
188
    {
189
        return $this->position;
190
    }
191
192
    /**
193
     * Set a separator to display between widgets in the group.
194
     *
195
     * @param string $separator
196
     *
197
     * @return $this
198
     */
199
    public function setSeparator($separator)
200
    {
201
        $this->separator = $separator;
202
203
        return $this;
204
    }
205
206
    /**
207
     * Setter for $this->wrapCallback.
208
     *
209
     * @param callable $callable
210
     *
211
     * @return $this
212
     */
213
    public function wrap(callable $callable)
214
    {
215
        $this->wrapCallback = $callable;
216
217
        return $this;
218
    }
219
220
    /**
221
     * Check if there are any widgets in the group.
222
     *
223
     * @return bool
224
     */
225
    public function any()
226
    {
227
        return !$this->isEmpty();
228
    }
229
230
    /**
231
     * Check if there are no widgets in the group.
232
     *
233
     * @return bool
234
     */
235
    public function isEmpty()
236
    {
237
        return empty($this->widgets);
238
    }
239
240
    /**
241
     * Count the number of widgets in this group.
242
     *
243
     * @return int
244
     */
245
    public function count()
246
    {
247
        $count = 0;
248
        foreach ($this->widgets as $position => $widgets) {
249
            $count += count($widgets);
250
        }
251
252
        return $count;
253
    }
254
255
    /**
256
     * Add a widget with a given type to the array.
257
     *
258
     * @param string $type
259
     * @param array  $arguments
260
     *
261
     * @return int
262
     */
263
    protected function addWidgetWithType($type, array $arguments = [])
264
    {
265
        if (!isset($this->widgets[$this->position])) {
266
            $this->widgets[$this->position] = [];
267
        }
268
269
        $id = $this->nextWidgetId;
270
        $this->widgets[$this->position][] = [
271
            'id'        => $id,
272
            'arguments' => $arguments,
273
            'type'      => $type,
274
        ];
275
276
        $this->resetPosition();
277
        $this->nextWidgetId++;
278
279
        return $id;
280
    }
281
282
    /**
283
     * Display a widget according to its type.
284
     *
285
     * @param $widget
286
     *
287
     * @return mixed
288
     */
289
    protected function displayWidget($widget)
290
    {
291
        $factory = $this->app->make($widget['type'] === 'sync' ? 'arrilot.widget' : 'arrilot.async-widget');
292
293
        return call_user_func_array([$factory, 'run'], $widget['arguments']);
294
    }
295
296
    /**
297
     * Reset the position property back to the default.
298
     * So it does not affect the next widget.
299
     */
300
    protected function resetPosition()
301
    {
302
        $this->position = 100;
303
    }
304
305
    /**
306
     * Wraps widget content in a special markup defined by $this->wrap().
307
     *
308
     * @param string $content
309
     * @param int    $index
310
     * @param int    $total
311
     *
312
     * @return string
313
     */
314
    protected function performWrap($content, $index, $total)
315
    {
316
        if (is_null($this->wrapCallback)) {
317
            return $content;
318
        }
319
320
        $callback = $this->wrapCallback;
321
322
        return $callback($content, $index, $total);
323
    }
324
}
325