Completed
Branch master (83a2f0)
by De Cramer
02:40
created

GridBuilder   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 433
Duplicated Lines 3.46 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 43
c 2
b 1
f 0
lcom 1
cbo 13
dl 15
loc 433
rs 8.3157

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like GridBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GridBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace eXpansion\Framework\Core\Model\Gui\Grid;
4
5
use eXpansion\Framework\Core\Model\Gui\Factory\LineFactory;
6
use eXpansion\Framework\Core\Model\Gui\Factory\PagerFactory;
7
use eXpansion\Framework\Core\Model\Gui\Factory\TitleLineFactory;
8
use eXpansion\Framework\Core\Model\Gui\Grid\Column\AbstractColumn;
9
use eXpansion\Framework\Core\Model\Gui\Grid\Column\ActionColumn;
10
use eXpansion\Framework\Core\Model\Gui\Grid\Column\InputColumn;
11
use eXpansion\Framework\Core\Model\Gui\Grid\Column\TextColumn;
12
use eXpansion\Framework\Core\Model\Gui\ManialinkFactoryInterface;
13
use eXpansion\Framework\Core\Model\Gui\ManialinkInterface;
14
use eXpansion\Framework\Core\Plugins\Gui\ActionFactory;
15
use eXpansion\Framework\Gui\Ui\Factory;
16
use FML\Controls\Frame;
17
use FML\Types\Renderable;
18
19
20
/**
21
 * Class GridBuilder
22
 *
23
 * @package eXpansion\Framework\Core\Model\Gui\Grid;
24
 * @author  oliver de Cramer <[email protected]>
25
 */
26
class GridBuilder
27
{
28
29
    /** @var  ActionFactory */
30
    protected $actionFactory;
31
32
    /** @var TitleLineFactory */
33
    protected $titleLineFactory;
34
35
    /** @var LineFactory */
36
    protected $lineFactory;
37
38
    /** @var PagerFactory */
39
    protected $pagerFactory;
40
41
    /** @var Factory */
42
    protected $uiFactory;
43
44
    /** @var DataCollectionInterface */
45
    protected $dataCollection;
46
47
    /** @var ManialinkInterface */
48
    protected $manialink;
49
50
    /** @var ManialinkFactoryInterface */
51
    protected $manialinkFactory;
52
53
    /** @var AbstractColumn[] */
54
    protected $columns;
55
56
    /** @var  float */
57
    protected $totalWidthCoefficency = 0.;
58
59
    /** @var int */
60
    protected $currentPage = 1;
61
62
    /** @var string */
63
    protected $pageKey;
64
65
    /** @var string */
66
    protected $actionPreviousPage;
67
    /** @var string */
68
    protected $actionNextPage;
69
    /** @var string */
70
    protected $actionLastPage;
71
    /** @var string */
72
    protected $actionFirstPage;
73
    /** @var  string */
74
    protected $actionGotoPage;
75
    /** @var string[] */
76
    protected $temporaryActions = [];
77
78
    /** @var array */
79
    protected $temporaryEntries = [];
80
81
82
    /**
83
     * GridBuilder constructor.
84
     *
85
     * @param ActionFactory $actionFactory
86
     * @param LineFactory $lineFactory
87
     * @param TitleLineFactory $titleLineFactory
88
     * @param PagerFactory $pagerFactory
89
     */
90
    public function __construct(
91
        ActionFactory $actionFactory,
92
        LineFactory $lineFactory,
93
        TitleLineFactory $titleLineFactory,
94
        PagerFactory $pagerFactory,
95
        Factory $uiFactory
96
    ) {
97
        $this->actionFactory = $actionFactory;
98
        $this->titleLineFactory = $titleLineFactory;
99
        $this->lineFactory = $lineFactory;
100
        $this->pagerFactory = $pagerFactory;
101
        $this->uiFactory = $uiFactory;
102
103
        $this->pageKey = "key_".spl_object_hash($this);
104
    }
105
106
    /**
107
     * Set the data collection.
108
     *
109
     * @param DataCollectionInterface $dataCollection
110
     *
111
     * @return $this
112
     */
113
    public function setDataCollection(DataCollectionInterface $dataCollection)
114
    {
115
        $this->dataCollection = $dataCollection;
116
117
        return $this;
118
    }
119
120
    /**
121
     * Set the manialink the content is generated for.
122
     *
123
     * @param ManialinkInterface $manialink
124
     *
125
     * @return $this
126
     */
127
    public function setManialink(ManialinkInterface $manialink)
128
    {
129
        $this->manialink = $manialink;
130
131
        $this->actionFirstPage = $this->actionFactory
132
            ->createManialinkAction($manialink, array($this, 'goToFirstPage'), []);
133
        $this->actionPreviousPage = $this->actionFactory
134
            ->createManialinkAction($manialink, array($this, 'goToPreviousPage'), []);
135
        $this->actionNextPage = $this->actionFactory
136
            ->createManialinkAction($manialink, array($this, 'goToNextPage'), []);
137
        $this->actionLastPage = $this->actionFactory
138
            ->createManialinkAction($manialink, array($this, 'goToLastPage'), []);
139
        $this->actionGotoPage = $this->actionFactory
140
            ->createManialinkAction($manialink, array($this, 'goToPage'), []);
141
142
        return $this;
143
    }
144
145
    /**
146
     * Set the manialink factory responsible with the manialink.
147
     *
148
     * @param ManialinkFactoryInterface $manialinkFactory
149
     *
150
     * @return $this
151
     */
152
    public function setManialinkFactory(ManialinkFactoryInterface $manialinkFactory)
153
    {
154
        $this->manialinkFactory = $manialinkFactory;
155
156
        return $this;
157
    }
158
159
    /**
160
     * @param      string $key
161
     * @param      string $name
162
     * @param      integer $widthCoefficiency
163
     * @param bool $sortable
164
     * @param bool $translatable
165
     *
166
     * @return $this
167
     */
168
    public function addTextColumn($key, $name, $widthCoefficiency, $sortable = false, $translatable = false)
169
    {
170
        $this->columns[] = new TextColumn($key, $name, $widthCoefficiency, $sortable, $translatable);
171
172
        return $this;
173
    }
174
175
    /**
176
     * @param      string $key
177
     * @param      string $name
178
     * @param      integer $widthCoefficiency
179
     * @param bool $sortable
180
     * @param bool $translatable
181
     *
182
     * @return $this
183
     */
184
    public function addInputColumn($key, $name, $widthCoefficiency)
185
    {
186
        $this->columns[] = new InputColumn($key, $name, $widthCoefficiency);
187
188
        return $this;
189
    }
190
191
192
    /**
193
     * Add an action into a column.
194
     *
195
     * @param string $key
196
     * @param string $name
197
     * @param integer $widthCoefficiency
198
     * @param $action
199
     * @param Renderable $renderer
200
     *
201
     * @return $this
202
     */
203
    public function addActionColumn($key, $name, $widthCoefficiency, $action, $renderer)
204
    {
205
        $this->columns[] = new ActionColumn($key, $name, $widthCoefficiency, $action, $renderer);
206
207
        return $this;
208
    }
209
210
    /**
211
     * Remove all columns.
212
     */
213
    public function resetColumns()
214
    {
215
        $this->columns = [];
216
        $this->totalWidthCoefficency = 0.;
217
    }
218
219
    /**
220
     * Build a grid.
221
     *
222
     * @param double $width
223
     * @param double $height
224
     *
225
     * @return Frame
226
     */
227
    public function build($width, $height)
228
    {
229
        foreach ($this->temporaryActions as $action) {
230
            $this->actionFactory->destroyAction($action);
231
        }
232
233
        $lineHeight = 5 + 0.5;
234
235
236
        $frame = new Frame();
237
        $frame->setPosition(0, 0);
238
        $frame->setSize($width, $height);
239
240
        $posY = 0.;
241
        $tooltip = $this->uiFactory->createTooltip();
242
        $frame->addChild($tooltip);
243
244
        // Generating headers.
245
        $data = [];
246
        foreach ($this->columns as $columnData) {
247
            $action = null;
248
            $sort = "";
249
            if ($columnData->getSortable() && $columnData->getSortColumn()) {
250
                $sort = $columnData->getSortDirection();
251
252
            }
253
            if ($columnData->getSortable()) {
254
                $action = $this->actionFactory->createManialinkAction(
255
                    $this->manialink,
256
                    [$this, 'sortColumn'],
257
                    ["key" => $columnData->getKey()]);
258
            }
259
260
            $data[] = [
261
                'title' => $columnData->getName(),
262
                'width' => $columnData->getWidthCoeficiency(),
263
                'translatable' => true,
264
                'sort' => $sort,
265
                'action' => $action,
266
            ];
267
        }
268
269
        $frame->addChild($this->titleLineFactory->create($frame->getWidth(), $data));
270
        $posY -= $lineHeight + 1;
271
272
        /*
273
         * Display the main content.
274
         */
275
        $this->dataCollection->setPageSize(floor(($frame->getHeight() + $posY - $lineHeight - 2) / $lineHeight));
276
277
        $lines = $this->dataCollection->getData($this->currentPage);
278
        $idx = 0;
279
        foreach ($lines as $i => $lineData) {
280
            $data = [];
281
            foreach ($this->columns as $columnData) {
282
                if ($columnData instanceof TextColumn) {
283
                    $data[] = [
284
                        'text' => $this->dataCollection->getLineData($lineData, $columnData->getKey()),
285
                        'width' => $columnData->getWidthCoeficiency(),
286
                        'translatable' => $columnData->getTranslatable(),
287
                    ];
288
                } elseif ($columnData instanceof ActionColumn) {
289
                    $action = $this->actionFactory
290
                        ->createManialinkAction($this->manialink, $columnData->getCallable(), $lineData);
291
                    $this->temporaryActions[] = $action;
292
                    $data[] = [
293
                        'renderer' => clone $columnData->getRenderer(),
294
                        'width' => $columnData->getWidthCoeficiency(),
295
                        'action' => $action,
296
                    ];
297
                } elseif ($columnData instanceof InputColumn) {
298
                    $value = $this->dataCollection->getLineData($lineData, $columnData->getKey());
299
300
                    $data[] = [
301
                        'input' => $value,
302
                        'index' => $i,
303
                        'tooltip' => $tooltip,
304
                        'width' => $columnData->getWidthCoeficiency(),
305
                    ];
306
                }
307
            }
308
            $line = $this->lineFactory->create($frame->getWidth(), $data, $idx++);
309
            $line->setPosition(0, $posY);
310
            $frame->addChild($line);
311
            $posY -= $lineHeight;
312
        }
313
314
        /*
315
         * Handle the pager.
316
         */
317
        $posY = ($frame->getHeight() - 9) * -1;
318
        $pager = $this->pagerFactory->create(
319
            $frame->getWidth(),
320
            $this->currentPage,
321
            $this->dataCollection->getLastPageNumber(),
322
            $this->actionFirstPage,
323
            $this->actionPreviousPage,
324
            $this->actionNextPage,
325
            $this->actionLastPage,
326
            $this->actionGotoPage
327
        );
328
        $pager->setPosition(($frame->getWidth() - $pager->getWidth()) / 2, $posY);
329
        $frame->addChild($pager);
330
331
        return $frame;
332
    }
333
334
    /**
335
     * Action callback to go to the first page.
336
     */
337
    public function goToFirstPage(ManialinkInterface $manialink, $login = null, $entries = [])
338
    {
339
        $this->updateDataCollection($entries);
340
        $this->changePage(1);
341
    }
342
343
    /**
344
     * Action callback to go to the previous page.
345
     */
346
    public function goToPreviousPage(ManialinkInterface $manialink, $login = null, $entries = [])
347
    {
348
        $this->updateDataCollection($entries);
349
        if ($this->currentPage - 1 >= 1) {
350
            $this->changePage($this->currentPage - 1);
351
        }
352
    }
353
354
    /**
355
     * Action callback to go to the next page.
356
     */
357
    public function goToNextPage(ManialinkInterface $manialink, $login = null, $entries = [])
358
    {
359
        $this->updateDataCollection($entries);
360
        if ($this->currentPage + 1 <= $this->dataCollection->getLastPageNumber()) {
361
            $this->changePage($this->currentPage + 1);
362
        }
363
    }
364
365
    public function goToPage(ManialinkInterface $manialink, $login = null, $entries = [])
366
    {
367
        if (array_key_exists("pager_gotopage", $entries)) {
368
            if (is_numeric($entries['pager_gotopage'])) {
369
                $page = (int)$entries['pager_gotopage'];
370
371
                $this->updateDataCollection($entries);
372
                if (($page >= 1) && ($page <= $this->dataCollection->getLastPageNumber())) {
373
                    $this->changePage($page);
374
                }
375
            }
376
        }
377
    }
378
379
380
    /**
381
     * Action callback to go to the last page.
382
     */
383
    public function goToLastPage(ManialinkInterface $manialink, $login = null, $entries = [])
384
    {
385
        $this->updateDataCollection($entries);
386
        $this->changePage($this->dataCollection->getLastPageNumber());
387
    }
388
389
    /**
390
     * Updates dataCollection from entries.
391
     */
392
    public function updateDataCollection($entries)
393
    {
394
        $process = false;
395
        $data = [];
396
        $start = ($this->currentPage - 1) * $this->dataCollection->getPageSize();
397
        foreach ($entries as $key => $value) {
398
            if (substr($key, 0, 6) == "entry_") {
399
                $array = explode("_", str_replace("entry_", "", $key));
400
                setType($value, $array[1]);
401
                $data[$array[0]] = $value;
402
                $process = true;
403
            }
404
        }
405
        if ($process) {
406
            $lines = $this->dataCollection->getData($this->currentPage);
407
            $counter = 0;
408
            foreach ($lines as $i => $lineData) {
409
                $newData = $lineData;
410
                foreach ($this->columns as $columnData) {
411
                    if ($columnData instanceof InputColumn) {
412
                        $newData[$columnData->getKey()] = $data[$counter];
413
                    }
414
                }
415
                $this->dataCollection->setDataByIndex($start + $counter, $newData);
416
                $counter++;
417
            }
418
        }
419
    }
420
421
    /** get dataCollection
422
     *
423
     * @return DataCollectionInterface
424
     */
425
    public function getDataCollection()
426
    {
427
        return $this->dataCollection;
428
    }
429
430
    /**
431
     * Handle page change & refresh user window.
432
     *
433
     * @param integer $page
434
     */
435
    protected function changePage($page)
436
    {
437
        $this->currentPage = $page;
438
        $this->manialinkFactory->update($this->manialink->getUserGroup());
439
    }
440
441
    public function sortColumn(ManialinkInterface $manialink, $login, $entries, $args)
442
    {
443
        foreach ($this->columns as $columnData) {
444
            if ($columnData->getKey() == $args['key']) {
445
                if ($columnData->getSortColumn()) {
446
                    $columnData->toggleSortDirection();
447
                } else {
448
                    $columnData->setSortColumn(true);
449
                }
450
                $this->dataCollection->setFiltersAndSort([], $columnData->getKey(), $columnData->getSortDirection());
451
            } else {
452
                $columnData->setSortColumn(false);
453
            }
454
        }
455
456
        $this->manialinkFactory->update($manialink->getUserGroup());
457
    }
458
}
459