PluginProbe
Tableberg – Simple Gutenberg Table Block / trunk
Tableberg – Simple Gutenberg Table Block vtrunk
1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 trunk 0.0.2 0.2.1 0.3.2 0.3.3 0.4.1 0.5.0 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 0.5.7 0.5.8 All 41 releases
tableberg / renderer / Table / TableAttrs.php

TableAttrs.php in Tableberg – Simple Gutenberg Table Block trunk, at renderer/Table/TableAttrs.php

738 lines 20.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Tableberg\Renderer\Table;
4
5 use Tableberg\Renderer\Attrs\NumberAttr;
6 use Tableberg\Renderer\Attrs\BoolAttr;
7 use Tableberg\Renderer\Attrs\StringAttr;
8 use Tableberg\Renderer\Attrs\Sides;
9 use Tableberg\Renderer\Attrs\Corners;
10
11 use function Tableberg\Renderer\getOrNull;
12
13 class TableAttrs {
14 /** @var NumberAttr */
15 public $version;
16
17 /** @var BoolAttr */
18 public $isExample;
19
20 /** @var TableConfig */
21 public $table;
22
23 /** @var array<int, RowConfig> */
24 public $rows;
25
26 /** @var array<int, ColumnConfig> */
27 public $columns;
28
29 /** @var array<string, CellData> */
30 public $cells;
31
32 /** @var array<string, array<string, mixed>> */
33 public $bindings;
34
35 /** @var CellDefaults */
36 public $cellDefaults;
37
38 /**
39 * Every attribute the table block carried, untouched. Pro registers
40 * table-level attributes of its own, so its renderer reads them from
41 * here rather than free having to know their names — mirrors
42 * CellData->attrs.
43 *
44 * @var array<string, mixed>
45 */
46 public $attrs;
47
48 /**
49 * @param array $data
50 * @return self
51 */
52 public static function from_array($data) {
53 $data = is_array($data) ? $data : [];
54 $defaults = Defaults::get_defaults();
55
56 $instance = new self();
57 $instance->attrs = $data;
58 $instance->version = new NumberAttr(
59 getOrNull($data['version']),
60 $defaults['version']
61 );
62 $instance->isExample = new BoolAttr(getOrNull($data['isExample']), $defaults['isExample']);
63 $instance->table = TableConfig::from_array(getOrNull($data['table']));
64 $instance->rows = self::parse_row_configs(getOrNull($data['rows']));
65 $instance->columns = self::parse_columns(getOrNull($data['columns']));
66 $instance->cells = self::parse_cells(getOrNull($data['cells']));
67 $instance->bindings = self::parse_bindings(getOrNull($data['bindings']));
68 $instance->cellDefaults = CellDefaults::from_array(getOrNull($data['cellDefaults']));
69
70 return $instance;
71 }
72
73 /** @return array<string, mixed> */
74 public static function get_table_defaults() {
75 $defaults = Defaults::get_defaults();
76
77 if (isset($defaults['table']) && is_array($defaults['table'])) {
78 return $defaults['table'];
79 }
80
81 if (isset($defaults['tableConfig']) && is_array($defaults['tableConfig'])) {
82 return $defaults['tableConfig'];
83 }
84
85 return [];
86 }
87
88 /** @return array<string, mixed> */
89 public static function get_cell_style_defaults() {
90 $defaults = Defaults::get_defaults();
91
92 if (
93 isset($defaults['cellDefaults']) &&
94 is_array($defaults['cellDefaults']) &&
95 isset($defaults['cellDefaults']['styles']) &&
96 is_array($defaults['cellDefaults']['styles'])
97 ) {
98 return array_merge(
99 ['cells' => []],
100 $defaults['cellDefaults']['styles']
101 );
102 }
103
104 if (isset($defaults['cellStyles']) && is_array($defaults['cellStyles'])) {
105 return array_merge(['cells' => []], $defaults['cellStyles']);
106 }
107
108 return ['cells' => []];
109 }
110
111 /** @return array<int, array{array{int, int}, array<int, mixed>}> */
112 public static function get_data_defaults() {
113 $defaults = Defaults::get_defaults();
114
115 if (
116 isset($defaults['data']) &&
117 is_array($defaults['data']) &&
118 isset($defaults['data']['cells']) &&
119 is_array($defaults['data']['cells'])
120 ) {
121 return $defaults['data']['cells'];
122 }
123
124 return [];
125 }
126
127 /** @return array<int, RowConfig> */
128 private static function parse_row_configs($data) {
129 if (!is_array($data)) {
130 return [];
131 }
132
133 $row_configs = [];
134
135 foreach ($data as $row => $row_config) {
136 $row_configs[(int) $row] = RowConfig::from_array($row_config);
137 }
138
139 return $row_configs;
140 }
141
142 /** @return array<int, ColumnConfig> */
143 private static function parse_columns($data) {
144 if (!is_array($data)) {
145 return [];
146 }
147
148 $columns = [];
149
150 foreach ($data as $column => $column_config) {
151 $columns[(int) $column] = ColumnConfig::from_array($column_config);
152 }
153
154 return $columns;
155 }
156
157 /** @return array<string, CellData> */
158 private static function parse_cells($data) {
159 if (!is_array($data)) {
160 return [];
161 }
162
163 $cells = [];
164
165 foreach ($data as $key => $cell) {
166 if (!is_string($key)) {
167 continue;
168 }
169
170 $cells[$key] = CellData::from_array($cell);
171 }
172
173 return $cells;
174 }
175
176 /** @return array<string, array<string, mixed>> */
177 private static function parse_bindings($data) {
178 if (!is_array($data)) {
179 return [];
180 }
181
182 $bindings = [];
183
184 foreach ($data as $key => $binding) {
185 if (!is_string($key) || !is_array($binding)) {
186 continue;
187 }
188
189 $bindings[$key] = $binding;
190 }
191
192 return $bindings;
193 }
194 }
195
196 class Data {
197 /** @var array<int, array{array{int, int}, array<int, CellElement>}> */
198 public $cells;
199
200 /** @return self */
201 public static function from_array($data) {
202 $data = is_array($data) ? $data : [];
203 $default_cells = TableAttrs::get_data_defaults();
204
205 $instance = new self();
206 $instance->cells = self::parse_cells(getOrNull($data['cells']), $default_cells);
207
208 return $instance;
209 }
210
211 /** @return array<int, array{array{int, int}, array<int, CellElement>}> */
212 private static function parse_cells($data, $default) {
213 if (!is_array($data)) {
214 return $default;
215 }
216
217 $cells = [];
218
219 foreach ($data as $cell) {
220 if (!is_array($cell[0])) {
221 continue;
222 }
223
224 $coords = [(int) $cell[0][0], (int) $cell[0][1]];
225 $elements = [];
226
227 if (is_array($cell[1])) {
228 foreach ($cell[1] as $element) {
229 $elements[] = CellElement::from_array($element);
230 }
231 }
232
233 $cells[] = [$coords, $elements];
234 }
235
236 return $cells;
237 }
238 }
239
240 class PaginationConfig {
241 /** @var BoolAttr */
242 public $enabled;
243
244 /** @var NumberAttr */
245 public $pageSize;
246
247 /** @var BoolAttr */
248 public $showPageNumbers;
249
250 /** @var BoolAttr */
251 public $showPrevNext;
252
253 /** @return self */
254 public static function from_array($data) {
255 $data = is_array($data) ? $data : [];
256 $table_defaults = TableAttrs::get_table_defaults();
257 $d = isset($table_defaults['pagination']) && is_array($table_defaults['pagination'])
258 ? $table_defaults['pagination']
259 : [];
260
261 $instance = new self();
262 $instance->enabled = new BoolAttr(getOrNull($data['enabled']), $d['enabled']);
263 $instance->pageSize = new NumberAttr(getOrNull($data['pageSize']), $d['pageSize']);
264 $instance->showPageNumbers = new BoolAttr(getOrNull($data['showPageNumbers']), $d['showPageNumbers']);
265 $instance->showPrevNext = new BoolAttr(getOrNull($data['showPrevNext']), $d['showPrevNext']);
266
267 return $instance;
268 }
269 }
270
271 class ResponsiveBreakpointConfig {
272 /** @var BoolAttr */
273 public $enabled;
274
275 /** @var NumberAttr */
276 public $maxWidth;
277
278 /** @var StringAttr */
279 public $mode;
280
281 /** @var BoolAttr */
282 public $transpose;
283
284 /** @var NumberAttr */
285 public $stackCount;
286
287 /** @var BoolAttr */
288 public $repeatFirstCol;
289
290 /**
291 * @param array|null $data
292 * @param array<string, mixed> $defaults
293 * @return self
294 */
295 public static function from_array($data, $defaults) {
296 $data = is_array($data) ? $data : [];
297
298 $instance = new self();
299 $instance->enabled = new BoolAttr(getOrNull($data['enabled']), $defaults['enabled']);
300 $instance->maxWidth = new NumberAttr(getOrNull($data['maxWidth']), $defaults['maxWidth']);
301 $instance->mode = new StringAttr(
302 getOrNull($data['mode']),
303 $defaults['mode'],
304 ['', 'scroll', 'stack']
305 );
306 $transposeInput = getOrNull($data['transpose']);
307 $legacyDirectionInput = getOrNull($data['direction']);
308 if ($transposeInput === null && is_string($legacyDirectionInput)) {
309 $transposeInput = $legacyDirectionInput === 'row';
310 }
311
312 $instance->transpose = new BoolAttr(
313 $transposeInput,
314 $defaults['transpose']
315 );
316 $instance->stackCount = new NumberAttr(
317 getOrNull($data['stackCount']),
318 $defaults['stackCount']
319 );
320
321 $repeatFirstColInput = getOrNull($data['repeatFirstCol']);
322 if ($repeatFirstColInput === null) {
323 $repeatFirstColInput = getOrNull($data['headerAsCol']);
324 }
325
326 $instance->repeatFirstCol = new BoolAttr(
327 $repeatFirstColInput,
328 $defaults['repeatFirstCol']
329 );
330
331 return $instance;
332 }
333 }
334
335 class ResponsiveConfig {
336 /** @var ResponsiveBreakpointConfig */
337 public $tablet;
338
339 /** @var ResponsiveBreakpointConfig */
340 public $mobile;
341
342 /** @return self */
343 public static function from_array($data) {
344 $data = is_array($data) ? $data : [];
345 $table_defaults = TableAttrs::get_table_defaults();
346 $defaults = isset($table_defaults['responsive']) && is_array($table_defaults['responsive'])
347 ? $table_defaults['responsive']
348 : [];
349
350 $instance = new self();
351 $instance->tablet = ResponsiveBreakpointConfig::from_array(
352 getOrNull($data['tablet']),
353 $defaults['tablet']
354 );
355 $instance->mobile = ResponsiveBreakpointConfig::from_array(
356 getOrNull($data['mobile']),
357 $defaults['mobile']
358 );
359
360 return $instance;
361 }
362 }
363
364 class CellSpacingConfig {
365 /** @var StringAttr */
366 public $horizontal;
367
368 /** @var StringAttr */
369 public $vertical;
370
371 /** @return self */
372 public static function from_array($data) {
373 $data = is_array($data) ? $data : [];
374 $table_defaults = TableAttrs::get_table_defaults();
375 $defaults = isset($table_defaults['cellSpacing']) && is_array($table_defaults['cellSpacing'])
376 ? $table_defaults['cellSpacing']
377 : [];
378
379 $instance = new self();
380 $instance->horizontal = new StringAttr(
381 getOrNull($data['horizontal']),
382 $defaults['horizontal']
383 );
384 $instance->vertical = new StringAttr(
385 getOrNull($data['vertical']),
386 $defaults['vertical']
387 );
388
389 return $instance;
390 }
391 }
392
393 class CellDefaults {
394 /** @var CellStyles */
395 public $styles;
396
397 /** @return self */
398 public static function from_array($data) {
399 $data = is_array($data) ? $data : [];
400
401 $instance = new self();
402 $instance->styles = CellStyles::from_array(getOrNull($data['styles']));
403
404 return $instance;
405 }
406 }
407
408 class CellData {
409 /** @var Span */
410 public $span;
411
412 /** @var StringAttr */
413 public $className;
414
415 /** @var array<int, CellElement> */
416 public $elements;
417
418 /** @var array<string, mixed>|null */
419 public $styles;
420
421 /** @var array<string, mixed>|null */
422 public $ribbon;
423
424 /**
425 * Every attribute the cell block carried, untouched. Pro registers cell
426 * attributes of its own, so its renderer reads them from here rather
427 * than free having to know their names.
428 *
429 * @var array<string, mixed>
430 */
431 public $attrs;
432
433 /** @return self */
434 public static function from_array($data) {
435 $data = is_array($data) ? $data : [];
436
437 $instance = new self();
438 $instance->attrs = $data;
439 $instance->span = Span::from_array(getOrNull($data['span']));
440 $instance->className = new StringAttr(getOrNull($data['className']), '');
441 $instance->elements = [];
442
443 $elements = getOrNull($data['elements']);
444 if (is_array($elements)) {
445 foreach ($elements as $element) {
446 $instance->elements[] = CellElement::from_array($element);
447 }
448 }
449
450 $styles = getOrNull($data['styles']);
451 $instance->styles = is_array($styles) ? $styles : null;
452
453 $ribbon = getOrNull($data['ribbon']);
454 $instance->ribbon = is_array($ribbon) ? $ribbon : null;
455
456 return $instance;
457 }
458 }
459
460 class TableConfig {
461 /** @var NumberAttr */
462 public $rows;
463
464 /** @var NumberAttr */
465 public $cols;
466
467 /** @var StringAttr */
468 public $className;
469
470 /** @var BoolAttr */
471 public $headerEnabled;
472
473 /** @var BoolAttr */
474 public $footerEnabled;
475
476 /** @var StringAttr */
477 public $caption;
478
479 /** @var StringAttr */
480 public $tableWidth;
481
482 /** @var StringAttr */
483 public $tableAlignment;
484
485 /** @var CellSpacingConfig */
486 public $cellSpacing;
487
488 /** @var Sides */
489 public $tableBorder;
490
491 /** @var Sides */
492 public $margin;
493
494 /** @var Sides */
495 public $padding;
496
497 /** @var BoolAttr */
498 public $fixedColumnWidths;
499
500 /** @var PaginationConfig */
501 public $pagination;
502
503 /** @var ResponsiveConfig */
504 public $responsive;
505
506 /** @return self */
507 public static function from_array($data) {
508 $data = is_array($data) ? $data : [];
509 $d = TableAttrs::get_table_defaults();
510
511 $instance = new self();
512 $instance->rows = new NumberAttr(getOrNull($data['rows']), $d['rows']);
513 $instance->cols = new NumberAttr(getOrNull($data['cols']), $d['cols']);
514 $instance->className = new StringAttr(getOrNull($data['className']), '');
515 $instance->headerEnabled = new BoolAttr(getOrNull($data['headerEnabled']), $d['headerEnabled']);
516 $instance->footerEnabled = new BoolAttr(getOrNull($data['footerEnabled']), $d['footerEnabled']);
517 $instance->caption = new StringAttr(getOrNull($data['caption']), $d['caption']);
518 $instance->tableWidth = new StringAttr(
519 getOrNull($data['tableWidth']),
520 $d['tableWidth']
521 );
522 $instance->tableAlignment = new StringAttr(
523 getOrNull($data['tableAlignment']),
524 $d['tableAlignment'],
525 ['left', 'center', 'right']
526 );
527 $instance->cellSpacing = CellSpacingConfig::from_array(getOrNull($data['cellSpacing']));
528 $instance->tableBorder = Sides::from_array(
529 getOrNull($data['tableBorder']),
530 $d['tableBorder']
531 );
532 $emptySides = ['top' => '', 'right' => '', 'bottom' => '', 'left' => ''];
533 $instance->margin = Sides::from_array(
534 getOrNull($data['margin']),
535 isset($d['margin']) && is_array($d['margin']) ? $d['margin'] : $emptySides
536 );
537 $instance->padding = Sides::from_array(
538 getOrNull($data['padding']),
539 isset($d['padding']) && is_array($d['padding']) ? $d['padding'] : $emptySides
540 );
541 $instance->fixedColumnWidths = new BoolAttr(
542 getOrNull($data['fixedColumnWidths']),
543 $d['fixedColumnWidths']
544 );
545 $instance->pagination = PaginationConfig::from_array(getOrNull($data['pagination']));
546 $instance->responsive = ResponsiveConfig::from_array(getOrNull($data['responsive']));
547
548 return $instance;
549 }
550 }
551
552 class CellStyles {
553 /** @var Sides */
554 public $padding;
555
556 /** @var StringAttr */
557 public $elementGap;
558
559 /** @var StringAttr */
560 public $verticalAlign;
561
562 /** @var StringAttr */
563 public $backgroundColor;
564
565 /** @var StringAttr */
566 public $headerBackgroundColor;
567
568 /** @var StringAttr */
569 public $footerBackgroundColor;
570
571 /** @var StringAttr */
572 public $evenRowBackgroundColor;
573
574 /** @var StringAttr */
575 public $oddRowBackgroundColor;
576
577 /** @var Sides */
578 public $border;
579
580 /** @var Corners */
581 public $borderRadius;
582
583 /** @var array<int, array{array{int, int}, array<string, mixed>}> */
584 public $cells;
585
586 /** @return self */
587 public static function from_array($data) {
588 $data = is_array($data) ? $data : [];
589 $d = TableAttrs::get_cell_style_defaults();
590
591 $instance = new self();
592 $instance->padding = Sides::from_array(getOrNull($data['padding']), $d['padding']);
593 $instance->elementGap = new StringAttr(
594 getOrNull($data['elementGap']),
595 $d['elementGap']
596 );
597 $instance->verticalAlign = new StringAttr(
598 getOrNull($data['verticalAlign']),
599 $d['verticalAlign'],
600 ['top', 'middle', 'bottom']
601 );
602 $instance->backgroundColor = new StringAttr(getOrNull($data['backgroundColor']), $d['backgroundColor']);
603 $instance->headerBackgroundColor = new StringAttr(getOrNull($data['headerBackgroundColor']), $d['headerBackgroundColor']);
604 $instance->footerBackgroundColor = new StringAttr(getOrNull($data['footerBackgroundColor']), $d['footerBackgroundColor']);
605 $instance->evenRowBackgroundColor = new StringAttr(getOrNull($data['evenRowBackgroundColor']), $d['evenRowBackgroundColor']);
606 $instance->oddRowBackgroundColor = new StringAttr(getOrNull($data['oddRowBackgroundColor']), $d['oddRowBackgroundColor']);
607 $instance->border = Sides::from_array(getOrNull($data['border']), $d['border']);
608 $instance->borderRadius = Corners::from_array(getOrNull($data['borderRadius']), $d['borderRadius']);
609 $instance->cells = is_array(getOrNull($data['cells'])) ? $data['cells'] : $d['cells'];
610
611 return $instance;
612 }
613 }
614
615 class Span {
616 /** @var NumberAttr */
617 public $rowSpan;
618
619 /** @var NumberAttr */
620 public $colSpan;
621
622 /**
623 * @param array|null $data
624 * @param array<string, int> $defaults
625 * @return self
626 */
627 public static function from_array($data, $defaults = ['rowSpan' => 1, 'colSpan' => 1]) {
628 $data = is_array($data) ? $data : [];
629
630 $defaultRowSpan = $defaults['rowSpan'];
631 $defaultColSpan = $defaults['colSpan'];
632
633 $instance = new self();
634 $instance->rowSpan = new NumberAttr(getOrNull($data['rowSpan']), $defaultRowSpan);
635 $instance->colSpan = new NumberAttr(getOrNull($data['colSpan']), $defaultColSpan);
636
637 return $instance;
638 }
639 }
640
641 class ColumnConfig {
642 /** @var StringAttr|null */
643 public $width;
644
645 /** @return self */
646 public static function from_array($data) {
647 $data = is_array($data) ? $data : [];
648 $width = getOrNull($data['width']);
649
650 $instance = new self();
651
652 if ($width === null || $width === '') {
653 $instance->width = null;
654 } else {
655 $instance->width = new StringAttr($width, '');
656 }
657
658 return $instance;
659 }
660 }
661
662 class RowConfig {
663 /** @var StringAttr|null */
664 public $height;
665
666 /**
667 * Every attribute the row block carried, untouched. Pro registers row
668 * attributes of its own (e.g. backgroundColor), so its renderer reads
669 * them from here rather than free having to know their names.
670 *
671 * @var array<string, mixed>
672 */
673 public $attrs;
674
675 /**
676 * @param array|null $data
677 * @return self
678 */
679 public static function from_array($data) {
680 $data = is_array($data) ? $data : [];
681 $height = getOrNull($data['height']);
682
683 $instance = new self();
684 $instance->attrs = $data;
685
686 if ($height === null || $height === '') {
687 $instance->height = null;
688 } else {
689 $instance->height = new StringAttr($height, '');
690 }
691
692 return $instance;
693 }
694 }
695
696 class CellElement {
697 /** @var StringAttr */
698 public $name;
699
700 /** @var array<string, mixed> */
701 public $attributes;
702
703 /** @var array<string, mixed>|null */
704 public $bindings;
705
706 /**
707 * @param array|null $data
708 * @param string $defaultName
709 * @param array<int, string>|null $allowedNames
710 * @return self
711 */
712 public static function from_array($data, $defaultName = 'text', $allowedNames = null) {
713 $data = is_array($data) ? $data : [];
714
715 if (!is_array($allowedNames)) {
716 $allowedNames = [
717 'text',
718 'button',
719 'image',
720 'list',
721 'icon',
722 'star-rating',
723 'custom-html',
724 'styled-list',
725 ];
726 }
727
728 $instance = new self();
729 $instance->name = new StringAttr(getOrNull($data['name']), $defaultName, $allowedNames);
730 $attributes = getOrNull($data['attributes']);
731 $instance->attributes = is_array($attributes) ? $attributes : [];
732 $bindings = getOrNull($data['bindings']);
733 $instance->bindings = is_array($bindings) ? $bindings : null;
734
735 return $instance;
736 }
737 }
738