PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.1.0
Tableberg – Simple Gutenberg Table Block v1.1.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 0.5.7 All 42 releases
tableberg / renderer / Migrations / TableBlockMigratorV3ToV4.php

TableBlockMigratorV3ToV4.php in Tableberg – Simple Gutenberg Table Block 1.1.0, at renderer/Migrations/TableBlockMigratorV3ToV4.php

201 lines 6.2 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\Migrations;
4
5 /**
6 * Migrates a v3 (faux-block era) table block into the v4 native-blocks
7 * format. Unlike the attr-only migrators, this replaces the WHOLE parsed
8 * block: slim v4 attrs + a real innerBlocks tree (rows -> cells -> elements).
9 *
10 * v3 shim innerBlocks (cell/element comments carrying only coords) are
11 * discarded — the attrs are canonical and the tree is rebuilt from them.
12 */
13 class TableBlockMigratorV3ToV4 {
14 const ELEMENT_NAMES = [
15 'text',
16 'button',
17 'image',
18 'list',
19 'styled-list',
20 'icon',
21 'star-rating',
22 'custom-html',
23 ];
24
25 /**
26 * @param array $block Parsed tableberg/table block with v3 attrs.
27 * @return array Parsed block in v4 shape.
28 */
29 public function migrate_block($block) {
30 if (!is_array($block) || !isset($block['attrs']) || !is_array($block['attrs'])) {
31 return $block;
32 }
33
34 $attrs = $block['attrs'];
35
36 $table = isset($attrs['table']) && is_array($attrs['table'])
37 ? $attrs['table']
38 : [];
39 $rowsCount = isset($table['rows']) && is_numeric($table['rows'])
40 ? (int) $table['rows']
41 : 0;
42 $colsCount = isset($table['cols']) && is_numeric($table['cols'])
43 ? (int) $table['cols']
44 : 0;
45
46 $cells = isset($attrs['cells']) && is_array($attrs['cells'])
47 ? $attrs['cells']
48 : [];
49 $rowConfigs = isset($attrs['rows']) && is_array($attrs['rows'])
50 ? $attrs['rows']
51 : [];
52
53 $covered = $this->compute_covered_positions($cells, $rowsCount, $colsCount);
54
55 $rowBlocks = [];
56 for ($row = 0; $row < $rowsCount; $row++) {
57 $cellBlocks = [];
58
59 for ($col = 0; $col < $colsCount; $col++) {
60 if (isset($covered["{$row},{$col}"])) {
61 continue;
62 }
63
64 $cell = isset($cells["{$row},{$col}"]) && is_array($cells["{$row},{$col}"])
65 ? $cells["{$row},{$col}"]
66 : [];
67
68 $cellBlocks[] = $this->build_cell_block($cell);
69 }
70
71 $rowAttrs = [];
72 $rowConfig = isset($rowConfigs[$row]) && is_array($rowConfigs[$row])
73 ? $rowConfigs[$row]
74 : [];
75 if (isset($rowConfig['height']) && is_string($rowConfig['height']) && $rowConfig['height'] !== '') {
76 $rowAttrs['height'] = $rowConfig['height'];
77 }
78
79 $rowBlocks[] = $this->make_block('tableberg/row', $rowAttrs, $cellBlocks);
80 }
81
82 // Slim v4 attrs: the cells map and per-row configs now live in the
83 // innerBlocks tree.
84 $newAttrs = $attrs;
85 unset($newAttrs['cells']);
86 unset($newAttrs['rows']);
87 $newAttrs['version'] = 4;
88
89 return $this->make_block('tableberg/table', $newAttrs, $rowBlocks);
90 }
91
92 /**
93 * @param array $cell v3 cell entry.
94 * @return array Parsed tableberg/cell block.
95 */
96 private function build_cell_block($cell) {
97 $cellAttrs = [];
98
99 foreach (['span', 'styles', 'ribbon', 'className'] as $key) {
100 if (isset($cell[$key])) {
101 $cellAttrs[$key] = $cell[$key];
102 }
103 }
104
105 $elementBlocks = [];
106 $elements = isset($cell['elements']) && is_array($cell['elements'])
107 ? $cell['elements']
108 : [];
109
110 foreach ($elements as $element) {
111 if (
112 !is_array($element) ||
113 !isset($element['name']) ||
114 !in_array($element['name'], self::ELEMENT_NAMES, true)
115 ) {
116 continue;
117 }
118
119 $elementAttrs = isset($element['attributes']) && is_array($element['attributes'])
120 ? $element['attributes']
121 : [];
122
123 if (isset($element['bindings']) && is_array($element['bindings']) && !empty($element['bindings'])) {
124 $elementAttrs['bindings'] = $element['bindings'];
125 }
126
127 $elementBlocks[] = $this->make_block(
128 'tableberg/' . $element['name'],
129 $elementAttrs,
130 []
131 );
132 }
133
134 return $this->make_block('tableberg/cell', $cellAttrs, $elementBlocks);
135 }
136
137 /**
138 * Positions covered by a rowSpan/colSpan anchor (excluding the anchor).
139 *
140 * @param array $cells
141 * @param int $rowsCount
142 * @param int $colsCount
143 * @return array<string, bool>
144 */
145 private function compute_covered_positions($cells, $rowsCount, $colsCount) {
146 $covered = [];
147
148 foreach ($cells as $key => $cell) {
149 if (!is_array($cell) || !isset($cell['span']) || !is_array($cell['span'])) {
150 continue;
151 }
152
153 $coords = explode(',', (string) $key);
154 if (count($coords) !== 2) {
155 continue;
156 }
157 $row = (int) $coords[0];
158 $col = (int) $coords[1];
159
160 $rowSpan = isset($cell['span']['rowSpan']) && is_numeric($cell['span']['rowSpan'])
161 ? max(1, (int) $cell['span']['rowSpan'])
162 : 1;
163 $colSpan = isset($cell['span']['colSpan']) && is_numeric($cell['span']['colSpan'])
164 ? max(1, (int) $cell['span']['colSpan'])
165 : 1;
166
167 for ($dr = 0; $dr < $rowSpan; $dr++) {
168 for ($dc = 0; $dc < $colSpan; $dc++) {
169 if ($dr === 0 && $dc === 0) {
170 continue;
171 }
172 $r = $row + $dr;
173 $c = $col + $dc;
174 if ($r >= $rowsCount || $c >= $colsCount) {
175 continue;
176 }
177 $covered["{$r},{$c}"] = true;
178 }
179 }
180 }
181
182 return $covered;
183 }
184
185 /**
186 * @param string $name
187 * @param array $attrs
188 * @param array $innerBlocks
189 * @return array
190 */
191 private function make_block($name, $attrs, $innerBlocks) {
192 return [
193 'blockName' => $name,
194 'attrs' => $attrs,
195 'innerBlocks' => $innerBlocks,
196 'innerHTML' => '',
197 'innerContent' => array_fill(0, count($innerBlocks), null),
198 ];
199 }
200 }
201