PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.2.0
Tableberg – Simple Gutenberg Table Block v1.2.0
1.2.0 1.1.5 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 All 43 releases
tableberg / renderer / Table / TableAttrs.php

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

773 lines 21.5 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, RowConfig> */
112 private static function parse_row_configs($data) {
113 if (!is_array($data)) {
114 return [];
115 }
116
117 $row_configs = [];
118
119 foreach ($data as $row => $row_config) {
120 $row_configs[(int) $row] = RowConfig::from_array($row_config);
121 }
122
123 return $row_configs;
124 }
125
126 /** @return array<int, ColumnConfig> */
127 private static function parse_columns($data) {
128 if (!is_array($data)) {
129 return [];
130 }
131
132 $columns = [];
133
134 foreach ($data as $column => $column_config) {
135 $columns[(int) $column] = ColumnConfig::from_array($column_config);
136 }
137
138 return $columns;
139 }
140
141 /** @return array<string, CellData> */
142 private static function parse_cells($data) {
143 if (!is_array($data)) {
144 return [];
145 }
146
147 $cells = [];
148
149 foreach ($data as $key => $cell) {
150 if (!is_string($key)) {
151 continue;
152 }
153
154 $cells[$key] = CellData::from_array($cell);
155 }
156
157 return $cells;
158 }
159
160 /** @return array<string, array<string, mixed>> */
161 private static function parse_bindings($data) {
162 if (!is_array($data)) {
163 return [];
164 }
165
166 $bindings = [];
167
168 foreach ($data as $key => $binding) {
169 if (!is_string($key) || !is_array($binding)) {
170 continue;
171 }
172
173 $bindings[$key] = $binding;
174 }
175
176 return $bindings;
177 }
178 }
179
180 class PaginationConfig {
181 /** @var BoolAttr */
182 public $enabled;
183
184 /** @var NumberAttr */
185 public $pageSize;
186
187 /** @var BoolAttr */
188 public $showPageNumbers;
189
190 /** @var BoolAttr */
191 public $showPrevNext;
192
193 /** @return self */
194 public static function from_array($data) {
195 $data = is_array($data) ? $data : [];
196 $table_defaults = TableAttrs::get_table_defaults();
197 $d = isset($table_defaults['pagination']) && is_array($table_defaults['pagination'])
198 ? $table_defaults['pagination']
199 : [];
200
201 $instance = new self();
202 $instance->enabled = new BoolAttr(getOrNull($data['enabled']), $d['enabled']);
203 $instance->pageSize = new NumberAttr(getOrNull($data['pageSize']), $d['pageSize']);
204 $instance->showPageNumbers = new BoolAttr(getOrNull($data['showPageNumbers']), $d['showPageNumbers']);
205 $instance->showPrevNext = new BoolAttr(getOrNull($data['showPrevNext']), $d['showPrevNext']);
206
207 return $instance;
208 }
209 }
210
211 class ResponsiveBreakpointConfig {
212 /** @var BoolAttr */
213 public $enabled;
214
215 /** @var NumberAttr */
216 public $maxWidth;
217
218 /** @var StringAttr */
219 public $mode;
220
221 /** @var BoolAttr */
222 public $transpose;
223
224 /** @var NumberAttr */
225 public $stackCount;
226
227 /** @var BoolAttr */
228 public $repeatFirstCol;
229
230 /**
231 * @param array|null $data
232 * @param array<string, mixed> $defaults
233 * @return self
234 */
235 public static function from_array($data, $defaults) {
236 $data = is_array($data) ? $data : [];
237
238 $instance = new self();
239 $instance->enabled = new BoolAttr(getOrNull($data['enabled']), $defaults['enabled']);
240 $instance->maxWidth = new NumberAttr(getOrNull($data['maxWidth']), $defaults['maxWidth']);
241 $instance->mode = new StringAttr(
242 getOrNull($data['mode']),
243 $defaults['mode'],
244 ['', 'scroll', 'stack']
245 );
246 $transposeInput = getOrNull($data['transpose']);
247 $legacyDirectionInput = getOrNull($data['direction']);
248 if ($transposeInput === null && is_string($legacyDirectionInput)) {
249 $transposeInput = $legacyDirectionInput === 'row';
250 }
251
252 $instance->transpose = new BoolAttr(
253 $transposeInput,
254 $defaults['transpose']
255 );
256 $instance->stackCount = new NumberAttr(
257 getOrNull($data['stackCount']),
258 $defaults['stackCount']
259 );
260
261 $repeatFirstColInput = getOrNull($data['repeatFirstCol']);
262 if ($repeatFirstColInput === null) {
263 $repeatFirstColInput = getOrNull($data['headerAsCol']);
264 }
265
266 $instance->repeatFirstCol = new BoolAttr(
267 $repeatFirstColInput,
268 $defaults['repeatFirstCol']
269 );
270
271 return $instance;
272 }
273 }
274
275 class ResponsiveConfig {
276 /** @var ResponsiveBreakpointConfig */
277 public $tablet;
278
279 /** @var ResponsiveBreakpointConfig */
280 public $mobile;
281
282 /** @return self */
283 public static function from_array($data) {
284 $data = is_array($data) ? $data : [];
285 $table_defaults = TableAttrs::get_table_defaults();
286 $defaults = isset($table_defaults['responsive']) && is_array($table_defaults['responsive'])
287 ? $table_defaults['responsive']
288 : [];
289
290 $instance = new self();
291 $instance->tablet = ResponsiveBreakpointConfig::from_array(
292 getOrNull($data['tablet']),
293 $defaults['tablet']
294 );
295 $instance->mobile = ResponsiveBreakpointConfig::from_array(
296 getOrNull($data['mobile']),
297 $defaults['mobile']
298 );
299
300 return $instance;
301 }
302 }
303
304 class CellSpacingConfig {
305 /** @var StringAttr */
306 public $horizontal;
307
308 /** @var StringAttr */
309 public $vertical;
310
311 /** @return self */
312 public static function from_array($data) {
313 $data = is_array($data) ? $data : [];
314 $table_defaults = TableAttrs::get_table_defaults();
315 $defaults = isset($table_defaults['cellSpacing']) && is_array($table_defaults['cellSpacing'])
316 ? $table_defaults['cellSpacing']
317 : [];
318
319 $instance = new self();
320 $instance->horizontal = new StringAttr(
321 getOrNull($data['horizontal']),
322 $defaults['horizontal']
323 );
324 $instance->vertical = new StringAttr(
325 getOrNull($data['vertical']),
326 $defaults['vertical']
327 );
328
329 return $instance;
330 }
331 }
332
333 class CellDefaults {
334 /** @var CellStyles */
335 public $styles;
336
337 /** @return self */
338 public static function from_array($data) {
339 $data = is_array($data) ? $data : [];
340
341 $instance = new self();
342 $instance->styles = CellStyles::from_array(getOrNull($data['styles']));
343
344 return $instance;
345 }
346 }
347
348 class CellData {
349 /** @var Span */
350 public $span;
351
352 /** @var StringAttr */
353 public $className;
354
355 /** @var array<int, CellElement> */
356 public $elements;
357
358 /** @var array<string, mixed>|null */
359 public $styles;
360
361 /** @var array<string, mixed>|null */
362 public $ribbon;
363
364 /**
365 * Every attribute the cell block carried, untouched. Pro registers cell
366 * attributes of its own, so its renderer reads them from here rather
367 * than free having to know their names.
368 *
369 * @var array<string, mixed>
370 */
371 public $attrs;
372
373 /** @return self */
374 public static function from_array($data) {
375 $data = is_array($data) ? $data : [];
376
377 $instance = new self();
378 $instance->attrs = $data;
379 $instance->span = Span::from_array(getOrNull($data['span']));
380 $instance->className = new StringAttr(getOrNull($data['className']), '');
381 $instance->elements = [];
382
383 $elements = getOrNull($data['elements']);
384 if (is_array($elements)) {
385 foreach ($elements as $element) {
386 $instance->elements[] = CellElement::from_array($element);
387 }
388 }
389
390 $styles = getOrNull($data['styles']);
391 $instance->styles = is_array($styles) ? $styles : null;
392
393 $ribbon = getOrNull($data['ribbon']);
394 $instance->ribbon = is_array($ribbon) ? $ribbon : null;
395
396 return $instance;
397 }
398 }
399
400 class TableConfig {
401 /** @var NumberAttr */
402 public $rows;
403
404 /** @var NumberAttr */
405 public $cols;
406
407 /** @var StringAttr */
408 public $className;
409
410 /** @var BoolAttr */
411 public $headerEnabled;
412
413 /** @var BoolAttr */
414 public $footerEnabled;
415
416 /** @var StringAttr */
417 public $caption;
418
419 /** @var StringAttr */
420 public $tableWidth;
421
422 /** @var StringAttr */
423 public $tableAlignment;
424
425 /** @var CellSpacingConfig */
426 public $cellSpacing;
427
428 /** @var Sides */
429 public $tableBorder;
430
431 /** @var TypographyConfig */
432 public $typography;
433
434 /** @var Sides */
435 public $margin;
436
437 /** @var Sides */
438 public $padding;
439
440 /** @var BoolAttr */
441 public $fixedColumnWidths;
442
443 /** @var PaginationConfig */
444 public $pagination;
445
446 /** @var ResponsiveConfig */
447 public $responsive;
448
449 /** @return self */
450 public static function from_array($data) {
451 $data = is_array($data) ? $data : [];
452 $d = TableAttrs::get_table_defaults();
453
454 $instance = new self();
455 $instance->rows = new NumberAttr(getOrNull($data['rows']), $d['rows']);
456 $instance->cols = new NumberAttr(getOrNull($data['cols']), $d['cols']);
457 $instance->className = new StringAttr(getOrNull($data['className']), '');
458 $instance->headerEnabled = new BoolAttr(getOrNull($data['headerEnabled']), $d['headerEnabled']);
459 $instance->footerEnabled = new BoolAttr(getOrNull($data['footerEnabled']), $d['footerEnabled']);
460 $instance->caption = new StringAttr(getOrNull($data['caption']), $d['caption']);
461 $instance->tableWidth = new StringAttr(
462 getOrNull($data['tableWidth']),
463 $d['tableWidth']
464 );
465 $instance->tableAlignment = new StringAttr(
466 getOrNull($data['tableAlignment']),
467 $d['tableAlignment'],
468 ['left', 'center', 'right']
469 );
470 $instance->cellSpacing = CellSpacingConfig::from_array(getOrNull($data['cellSpacing']));
471 $instance->tableBorder = Sides::from_array(
472 getOrNull($data['tableBorder']),
473 $d['tableBorder']
474 );
475 $instance->typography = TypographyConfig::from_array(
476 getOrNull($data['typography'])
477 );
478 $emptySides = ['top' => '', 'right' => '', 'bottom' => '', 'left' => ''];
479 $instance->margin = Sides::from_array(
480 getOrNull($data['margin']),
481 isset($d['margin']) && is_array($d['margin']) ? $d['margin'] : $emptySides
482 );
483 $instance->padding = Sides::from_array(
484 getOrNull($data['padding']),
485 isset($d['padding']) && is_array($d['padding']) ? $d['padding'] : $emptySides
486 );
487 $instance->fixedColumnWidths = new BoolAttr(
488 getOrNull($data['fixedColumnWidths']),
489 $d['fixedColumnWidths']
490 );
491 $instance->pagination = PaginationConfig::from_array(getOrNull($data['pagination']));
492 $instance->responsive = ResponsiveConfig::from_array(getOrNull($data['responsive']));
493
494 return $instance;
495 }
496 }
497
498 /**
499 * Table-wide typography: the same options the core Table block offers, set on
500 * the table element so the cells inherit them.
501 */
502 class TypographyConfig {
503 /** @var StringAttr */
504 public $fontFamily;
505
506 /** @var StringAttr */
507 public $fontSize;
508
509 /** @var StringAttr */
510 public $fontStyle;
511
512 /** @var StringAttr */
513 public $fontWeight;
514
515 /** @var StringAttr */
516 public $lineHeight;
517
518 /** @var StringAttr */
519 public $letterSpacing;
520
521 /** @var StringAttr */
522 public $textDecoration;
523
524 /** @var StringAttr */
525 public $textTransform;
526
527 /** @return self */
528 public static function from_array($data) {
529 $data = is_array($data) ? $data : [];
530 $tableDefaults = TableAttrs::get_table_defaults();
531 $d = isset($tableDefaults['typography']) && is_array($tableDefaults['typography'])
532 ? $tableDefaults['typography']
533 : [];
534
535 $instance = new self();
536 foreach (
537 [
538 'fontFamily',
539 'fontSize',
540 'fontStyle',
541 'fontWeight',
542 'lineHeight',
543 'letterSpacing',
544 'textDecoration',
545 'textTransform',
546 ] as $property
547 ) {
548 $instance->{$property} = new StringAttr(
549 getOrNull($data[$property]),
550 isset($d[$property]) ? $d[$property] : ''
551 );
552 }
553
554 return $instance;
555 }
556
557 /**
558 * The typography as `property: value` declarations, skipping everything
559 * the user has not set so the theme keeps deciding.
560 *
561 * @return array<int, string>
562 */
563 public function asStyles() {
564 $properties = [
565 'font-family' => $this->fontFamily,
566 'font-size' => $this->fontSize,
567 'font-style' => $this->fontStyle,
568 'font-weight' => $this->fontWeight,
569 'line-height' => $this->lineHeight,
570 'letter-spacing' => $this->letterSpacing,
571 'text-decoration' => $this->textDecoration,
572 'text-transform' => $this->textTransform,
573 ];
574
575 $styles = [];
576
577 foreach ($properties as $property => $attr) {
578 if ($attr->isNotEmpty()) {
579 $styles[] = $property . ': ' . $attr->asAttr();
580 }
581 }
582
583 return $styles;
584 }
585 }
586
587 class CellStyles {
588 /** @var Sides */
589 public $padding;
590
591 /** @var StringAttr */
592 public $elementGap;
593
594 /** @var StringAttr */
595 public $verticalAlign;
596
597 /** @var StringAttr */
598 public $backgroundColor;
599
600 /** @var StringAttr */
601 public $headerBackgroundColor;
602
603 /** @var StringAttr */
604 public $footerBackgroundColor;
605
606 /** @var StringAttr */
607 public $evenRowBackgroundColor;
608
609 /** @var StringAttr */
610 public $oddRowBackgroundColor;
611
612 /** @var Sides */
613 public $border;
614
615 /** @var Corners */
616 public $borderRadius;
617
618 /** @var array<int, array{array{int, int}, array<string, mixed>}> */
619 public $cells;
620
621 /** @return self */
622 public static function from_array($data) {
623 $data = is_array($data) ? $data : [];
624 $d = TableAttrs::get_cell_style_defaults();
625
626 $instance = new self();
627 $instance->padding = Sides::from_array(getOrNull($data['padding']), $d['padding']);
628 $instance->elementGap = new StringAttr(
629 getOrNull($data['elementGap']),
630 $d['elementGap']
631 );
632 $instance->verticalAlign = new StringAttr(
633 getOrNull($data['verticalAlign']),
634 $d['verticalAlign'],
635 ['top', 'middle', 'bottom']
636 );
637 $instance->backgroundColor = new StringAttr(getOrNull($data['backgroundColor']), $d['backgroundColor']);
638 $instance->headerBackgroundColor = new StringAttr(getOrNull($data['headerBackgroundColor']), $d['headerBackgroundColor']);
639 $instance->footerBackgroundColor = new StringAttr(getOrNull($data['footerBackgroundColor']), $d['footerBackgroundColor']);
640 $instance->evenRowBackgroundColor = new StringAttr(getOrNull($data['evenRowBackgroundColor']), $d['evenRowBackgroundColor']);
641 $instance->oddRowBackgroundColor = new StringAttr(getOrNull($data['oddRowBackgroundColor']), $d['oddRowBackgroundColor']);
642 $instance->border = Sides::from_array(getOrNull($data['border']), $d['border']);
643 $instance->borderRadius = Corners::from_array(getOrNull($data['borderRadius']), $d['borderRadius']);
644 $instance->cells = is_array(getOrNull($data['cells'])) ? $data['cells'] : $d['cells'];
645
646 return $instance;
647 }
648 }
649
650 class Span {
651 /** @var NumberAttr */
652 public $rowSpan;
653
654 /** @var NumberAttr */
655 public $colSpan;
656
657 /**
658 * @param array|null $data
659 * @param array<string, int> $defaults
660 * @return self
661 */
662 public static function from_array($data, $defaults = ['rowSpan' => 1, 'colSpan' => 1]) {
663 $data = is_array($data) ? $data : [];
664
665 $defaultRowSpan = $defaults['rowSpan'];
666 $defaultColSpan = $defaults['colSpan'];
667
668 $instance = new self();
669 $instance->rowSpan = new NumberAttr(getOrNull($data['rowSpan']), $defaultRowSpan);
670 $instance->colSpan = new NumberAttr(getOrNull($data['colSpan']), $defaultColSpan);
671
672 return $instance;
673 }
674 }
675
676 class ColumnConfig {
677 /** @var StringAttr|null */
678 public $width;
679
680 /** @return self */
681 public static function from_array($data) {
682 $data = is_array($data) ? $data : [];
683 $width = getOrNull($data['width']);
684
685 $instance = new self();
686
687 if ($width === null || $width === '') {
688 $instance->width = null;
689 } else {
690 $instance->width = new StringAttr($width, '');
691 }
692
693 return $instance;
694 }
695 }
696
697 class RowConfig {
698 /** @var StringAttr|null */
699 public $height;
700
701 /**
702 * Every attribute the row block carried, untouched. Pro registers row
703 * attributes of its own (e.g. backgroundColor), so its renderer reads
704 * them from here rather than free having to know their names.
705 *
706 * @var array<string, mixed>
707 */
708 public $attrs;
709
710 /**
711 * @param array|null $data
712 * @return self
713 */
714 public static function from_array($data) {
715 $data = is_array($data) ? $data : [];
716 $height = getOrNull($data['height']);
717
718 $instance = new self();
719 $instance->attrs = $data;
720
721 if ($height === null || $height === '') {
722 $instance->height = null;
723 } else {
724 $instance->height = new StringAttr($height, '');
725 }
726
727 return $instance;
728 }
729 }
730
731 class CellElement {
732 /** @var StringAttr */
733 public $name;
734
735 /** @var array<string, mixed> */
736 public $attributes;
737
738 /** @var array<string, mixed>|null */
739 public $bindings;
740
741 /**
742 * @param array|null $data
743 * @param string $defaultName
744 * @param array<int, string>|null $allowedNames
745 * @return self
746 */
747 public static function from_array($data, $defaultName = 'text', $allowedNames = null) {
748 $data = is_array($data) ? $data : [];
749
750 if (!is_array($allowedNames)) {
751 $allowedNames = [
752 'text',
753 'button',
754 'image',
755 'list',
756 'icon',
757 'star-rating',
758 'custom-html',
759 'styled-list',
760 ];
761 }
762
763 $instance = new self();
764 $instance->name = new StringAttr(getOrNull($data['name']), $defaultName, $allowedNames);
765 $attributes = getOrNull($data['attributes']);
766 $instance->attributes = is_array($attributes) ? $attributes : [];
767 $bindings = getOrNull($data['bindings']);
768 $instance->bindings = is_array($bindings) ? $bindings : null;
769
770 return $instance;
771 }
772 }
773