Table::getFormName()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 3
nc 4
nop 0
crap 3
1
<?php
2
3
namespace kalanis\kw_table\core;
4
5
6
use kalanis\kw_connect\core\ConnectException;
7
use kalanis\kw_connect\core\Interfaces\IIterableConnector;
8
use kalanis\kw_paging\Interfaces\IOutput;
9
use kalanis\kw_table\core\Interfaces\Form\IField;
10
use kalanis\kw_table\core\Interfaces\Form\IFilterForm;
11
use kalanis\kw_table\core\Interfaces\Table\IColumn;
12
use kalanis\kw_table\core\Interfaces\Table\IRule;
13
14
15
/**
16
 * Class Table
17
 * @package kalanis\kw_table\core
18
 * Main table render
19
 */
20
class Table
21
{
22
    public const PAGER_LIMIT_DEFAULT = 30;
23
24
    protected ?IIterableConnector $dataSetConnector = null;
25
26
    /** @var IColumn[] */
27
    protected array $columns = [];
28
29
    /** @var Table\Rows\ARow[] */
30
    protected array $callRows = [];
31
32
    /** @var string[] */
33
    protected array $classes = ['table', 'table-bordered', 'table-striped', 'table-hover', 'table-condensed', 'bootstrap-datatable', 'listtable'];
34
35
    protected ?IOutput $pager = null;
36
37
    protected ?Table\Order $order = null;
38
39
    protected ?Table\Filter $headerFilter = null;
40
41
    protected ?Table\Filter $footerFilter = null;
42
43
    protected ?Table\AOutput $output = null;
44
45
    /** @var Table\Internal\Row[]|Table[] */
46
    protected array $tableData = [];
47
48
    /** @var array<string, string> */
49
    protected array $defaultHeaderFilterFieldAttributes = [];
50
51
    /** @var array<string, string>  */
52
    protected array $defaultFooterFilterFieldAttributes = [];
53
54
    protected bool $showPagerOnHead = false;
55
    protected bool $showPagerOnFoot = true;
56
57
    /**
58
     * @param IIterableConnector|null $dataSetConnector
59
     */
60 31
    public function __construct(IIterableConnector $dataSetConnector = null)
61
    {
62 31
        if (!is_null($dataSetConnector)) {
63 5
            $this->addDataSetConnector($dataSetConnector);
64
        }
65 31
    }
66
67
    /**
68
     * Add external function to row for processing data
69
     * @param string $function
70
     * @param string[] $arguments
71
     * @return mixed|null|void
72
     */
73 1
    public function __call($function, $arguments)
74
    {
75 1
        if (preg_match('/^row(.*)$/', $function, $matches)) {
76 1
            $this->callRows[] = new Table\Rows\FunctionRow($matches[1], $arguments);
77
        }
78 1
    }
79
80
    /**
81
     * Add style class to whole row depending on the rule
82
     * @param string $class
83
     * @param IRule  $rule
84
     * @param string $cell
85
     */
86 1
    public function rowClass(string $class, IRule $rule, $cell): void
87
    {
88 1
        $this->callRows[] = new Table\Rows\ClassRow($class, $rule, $cell);
89 1
    }
90
91 11
    public function addOrder(Table\Order $order): self
92
    {
93 11
        $this->order = $order;
94 11
        return $this;
95
    }
96
97 5
    public function addHeaderFilter(IFilterForm $formConnector): self
98
    {
99 5
        $this->headerFilter = new Table\Filter($formConnector);
100 5
        return $this;
101
    }
102
103 1
    public function addFooterFilter(IFilterForm $formConnector): self
104
    {
105 1
        $this->footerFilter = new Table\Filter($formConnector);
106 1
        return $this;
107
    }
108
109
    /**
110
     * @param array<string, string> $attributes
111
     * @return $this
112
     */
113 1
    public function setDefaultHeaderFilterFieldAttributes(array $attributes): self
114
    {
115 1
        $this->defaultHeaderFilterFieldAttributes = $attributes;
116 1
        return $this;
117
    }
118
119
    /**
120
     * @param array<string, string> $attributes
121
     * @return $this
122
     */
123 1
    public function setDefaultFooterFilterFieldAttributes(array $attributes): self
124
    {
125 1
        $this->defaultFooterFilterFieldAttributes = $attributes;
126 1
        return $this;
127
    }
128
129 7
    public function addPager(IOutput $pager): self
130
    {
131 7
        $this->pager = $pager;
132 7
        return $this;
133
    }
134
135
    /**
136
     * Basic order
137
     * @param string $columnName
138
     * @param string $order
139
     * @throws TableException
140
     * @return $this
141
     */
142 9
    public function addOrdering(string $columnName, string $order = Table\Order::ORDER_ASC): self
143
    {
144 9
        $this->getOrder()->addOrdering($columnName, $order);
145 9
        return $this;
146
    }
147
148
    /**
149
     * More important order when some is already set
150
     * @param string $columnName
151
     * @param string $order
152
     * @throws TableException
153
     * @return $this
154
     */
155 1
    public function addPrimaryOrdering(string $columnName, string $order = Table\Order::ORDER_ASC): self
156
    {
157 1
        $this->getOrder()->addPrependOrdering($columnName, $order);
158 1
        return $this;
159
    }
160
161
    /**
162
     * @throws TableException
163
     * @return IOutput
164
     */
165 18
    public function getPager(): IOutput
166
    {
167 18
        if (empty($this->pager)) {
168 11
            throw new TableException('Need to set paging library first!');
169
        }
170 7
        return $this->pager;
171
    }
172
173
    /**
174
     * @return IOutput|null
175
     */
176 1
    public function getPagerOrNull(): ?IOutput
177
    {
178 1
        return $this->pager;
179
    }
180
181
    /**
182
     * @throws TableException
183
     * @return Table\Order
184
     */
185 15
    public function getOrder(): Table\Order
186
    {
187 15
        if (empty($this->order)) {
188 4
            throw new TableException('Need to set order library first!');
189
        }
190 11
        return $this->order;
191
    }
192
193
    /**
194
     * @return Table\Order|null
195
     */
196 10
    public function getOrderOrNull(): ?Table\Order
197
    {
198 10
        return $this->order;
199
    }
200
201 9
    public function getHeaderFilter(): ?Table\Filter
202
    {
203 9
        return $this->headerFilter;
204
    }
205
206 2
    public function getFooterFilter(): ?Table\Filter
207
    {
208 2
        return $this->footerFilter;
209
    }
210
211 2
    public function getFormName(): string
212
    {
213 2
        return $this->headerFilter ? $this->headerFilter->getFormName() : ( $this->footerFilter ? $this->footerFilter->getFormName() : '' );
214
    }
215
216 17
    public function setOutput(Table\AOutput $output): void
217
    {
218 17
        $this->output = $output;
219 17
    }
220
221 2
    public function getOutput(): ?Table\AOutput
222
    {
223 2
        return $this->output;
224
    }
225
226
    /**
227
     * Change data source
228
     * @param IIterableConnector $dataSetConnector
229
     * @return $this
230
     */
231 27
    public function addDataSetConnector(IIterableConnector $dataSetConnector): self
232
    {
233 27
        $this->dataSetConnector = $dataSetConnector;
234 27
        return $this;
235
    }
236
237
    /**
238
     * @throws TableException
239
     * @return IIterableConnector
240
     */
241 24
    public function getDataSetConnector(): IIterableConnector
242
    {
243 24
        if (empty($this->dataSetConnector)) {
244 1
            throw new TableException('Need to set dataset connector library first!');
245
        }
246 23
        return $this->dataSetConnector;
247
    }
248
249
    /**
250
     * Returns column to another update
251
     * @param int $position
252
     * @return IColumn|null
253
     */
254 1
    public function getColumn(int $position): ?IColumn
255
    {
256 1
        return $this->columns[$position] ?? null ;
257
    }
258
259
    /**
260
     * Return columns
261
     * @return Table\Internal\Row[]|Table[]
262
     */
263 17
    public function &getTableData(): array
264
    {
265 17
        return $this->tableData;
266
    }
267
268
    /**
269
     * @return IColumn[]
270
     */
271 17
    public function &getColumns(): array
272
    {
273 17
        return $this->columns;
274
    }
275
276
    /**
277
     * Return classes used for styles
278
     * @return string[]
279
     */
280 1
    public function &getClasses(): array
281
    {
282 1
        return $this->classes;
283
    }
284
285 1
    public function getClassesInString(): string
286
    {
287 1
        if (!empty($this->classes)) {
288 1
            return implode(' ', $this->classes);
289
        } else {
290 1
            return '';
291
        }
292
    }
293
294
    /**
295
     * @param string  $headerText
296
     * @param IColumn $column
297
     * @param IField|null $headerFilterField
298
     * @param IField|null $footerFilterField
299
     * @throws TableException
300
     * @return $this
301
     */
302 10
    public function addOrderedColumn(string $headerText, IColumn $column, ?IField $headerFilterField = null, ?IField $footerFilterField = null): self
303
    {
304 10
        if ($column->canOrder()) {
305 10
            $this->getOrder()->addColumn($column);
306
        }
307
308 9
        $this->addColumn($headerText, $column, $headerFilterField, $footerFilterField);
309
310 9
        return $this;
311
    }
312
313
    /**
314
     * @param string $headerText
315
     * @param IColumn $column
316
     * @param IField|null $headerFilterField
317
     * @param IField|null $footerFilterField
318
     * @throws TableException
319
     * @return $this
320
     */
321 26
    public function addColumn(string $headerText, IColumn $column, ?IField $headerFilterField = null, ?IField $footerFilterField = null): self
322
    {
323 26
        $column->setHeaderText($headerText);
324
325 26
        if (isset($headerFilterField)) {
326 6
            $headerFilterField->setAttributes($this->defaultHeaderFilterFieldAttributes);
327 6
            $column->setHeaderFiltering($headerFilterField);
328
        }
329
330 26
        if ($column->hasHeaderFilterField() && $this->headerFilter) {
331 5
            $this->headerFilter->addHeaderColumn($column);
332
        }
333
334 26
        if (isset($footerFilterField)) {
335 2
            $footerFilterField->setAttributes($this->defaultFooterFilterFieldAttributes);
336 2
            $column->setFooterFiltering($footerFilterField);
337
        }
338
339 26
        if ($column->hasFooterFilterField() && $this->footerFilter) {
340 1
            $this->footerFilter->addFooterColumn($column);
341
        }
342
343 26
        $this->columns[] = $column;
344
345 26
        return $this;
346
    }
347
348
    /**
349
     * Add Css class to the table
350
     * @param string $class
351
     */
352 1
    public function addClass(string $class): void
353
    {
354 1
        $this->classes[] = $class;
355 1
    }
356
357
    /**
358
     * Remover Css class from the table
359
     * @param string $class
360
     */
361 1
    public function removeClass($class): void
362
    {
363 1
        if (($key = array_search($class, $this->classes)) !== false) {
364 1
            unset($this->classes[$key]);
365
        }
366 1
    }
367
368
    /**
369
     * Render complete table - just helper method
370
     * @throws ConnectException
371
     * @throws TableException
372
     * @return string
373
     */
374 20
    public function render(): string
375
    {
376 20
        $this->translateData();
377 18
        if (!$this->output) {
378 1
            throw new TableException('Need to set output first!');
379
        }
380 17
        return $this->output->render();
381
    }
382
383
    /**
384
     * Update columns to readable format
385
     * @throws ConnectException
386
     * @throws TableException
387
     */
388 25
    public function translateData(): void
389
    {
390 25
        if (is_null($this->dataSetConnector)) {
391 1
            throw new TableException('Cannot create table from empty dataset');
392
        }
393
394 24
        if (empty($this->columns)) {
395 1
            throw new TableException('You need to define at least one column');
396
        }
397
398 23
        $this->applyFilter();
399 23
        $this->applyOrder();
400 23
        $this->applyPager();
401
402 23
        $this->getDataSetConnector()->fetchData();
403
404 23
        foreach ($this->getDataSetConnector() as $source) {
405 21
            $rowData = new Table\Internal\Row();
406 21
            $rowData->setSource($source);
407
408 21
            foreach ($this->callRows as $call) {
409 1
                call_user_func_array([$rowData, $call->getFunctionName()], $call->getFunctionArgs());
410
            }
411
412 21
            foreach ($this->columns as $column) {
413 21
                $col = clone $column;
414 21
                $rowData->addColumn($col);
415
            }
416
417 21
            $this->tableData[] = $rowData;
418
        }
419 23
    }
420
421
    /**
422
     * @throws ConnectException
423
     * @throws TableException
424
     * @return $this
425
     */
426 23
    protected function applyFilter(): self
427
    {
428 23
        if (empty($this->headerFilter)) {
429 18
            return $this;
430
        }
431
432 5
        $this->headerFilter->process();
433
434 5
        foreach ($this->columns as $column) {
435 5
            if ($this->headerFilter->hasValue($column)) {
436
437 5
                $filterField = $column->getHeaderFilterField();
438 5
                if ($filterField) {
439 5
                    $filterField->setDataSourceConnector($this->getDataSetConnector());
440 5
                    $this->getDataSetConnector()->setFiltering(
441 5
                        $column->getSourceName(),
442 5
                        $filterField->getFilterAction(),
443 5
                        $this->headerFilter->getValue($column)
444
                    );
445
                }
446
            }
447
        }
448 5
        return $this;
449
    }
450
451
    /**
452
     * @throws ConnectException
453
     * @throws TableException
454
     * @return $this
455
     */
456 23
    protected function applyOrder(): self
457
    {
458 23
        if (empty($this->order)) {
459 12
            return $this;
460
        }
461
462 11
        $this->getOrder()->process();
463 11
        foreach ($this->getOrder()->getOrdering() as $attributes) {
464
            /** @var Table\Internal\Attributes $attributes */
465 11
            $this->getDataSetConnector()->setOrdering($attributes->getColumnName(), $attributes->getProperty());
466
        }
467 11
        return $this;
468
    }
469
470
    /**
471
     * @throws ConnectException
472
     * @throws TableException
473
     * @return $this
474
     */
475 23
    protected function applyPager(): self
476
    {
477 23
        if (empty($this->pager)) {
478 16
            return $this;
479
        }
480
481 7
        if (empty($this->getPager()->getPager()->getMaxResults())) {
482 7
            $this->getPager()->getPager()->setMaxResults($this->getDataSetConnector()->getTotalCount());
483
        }
484 7
        $this->getDataSetConnector()->setPagination(
485 7
            $this->getPager()->getPager()->getOffset(),
486 7
            $this->getPager()->getPager()->getLimit()
487
        );
488 7
        return $this;
489
    }
490
491 3
    public function rowCount(): int
492
    {
493 3
        return count($this->tableData);
494
    }
495
496 3
    public function colCount(): int
497
    {
498 3
        return count($this->columns);
499
    }
500
501 1
    public function showPagerOnHead(): bool
502
    {
503 1
        return $this->showPagerOnHead;
504
    }
505
506 1
    public function showPagerOnFoot(): bool
507
    {
508 1
        return $this->showPagerOnFoot;
509
    }
510
}
511