PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.1.5
Tableberg – Simple Gutenberg Table Block v1.1.5
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.5, at renderer/Migrations/TableBlockMigratorV3ToV4.php

198 lines 6.3 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 $rowConfig = isset($rowConfigs[$row]) && is_array($rowConfigs[$row])
72 ? $rowConfigs[$row]
73 : [];
74
75 // Preserve every registered row attribute, including Pro-owned
76 // and future fields this migrator does not know by name.
77 $rowBlocks[] = $this->make_block('tableberg/row', $rowConfig, $cellBlocks);
78 }
79
80 // Slim v4 attrs: the cells map and per-row configs now live in the
81 // innerBlocks tree.
82 $newAttrs = $attrs;
83 unset($newAttrs['cells']);
84 unset($newAttrs['rows']);
85 $newAttrs['version'] = 4;
86
87 return $this->make_block('tableberg/table', $newAttrs, $rowBlocks);
88 }
89
90 /**
91 * @param array $cell v3 cell entry.
92 * @return array Parsed tableberg/cell block.
93 */
94 private function build_cell_block($cell) {
95 // Everything the cell carries becomes a block attribute, not just
96 // the keys this file knows about — pro registers cell attributes of
97 // its own and they must survive the migration. `elements` is the one
98 // exception: it becomes the cell's inner blocks below.
99 $cellAttrs = is_array($cell) ? $cell : [];
100 unset($cellAttrs['elements']);
101
102 $elementBlocks = [];
103 $elements = isset($cell['elements']) && is_array($cell['elements'])
104 ? $cell['elements']
105 : [];
106
107 foreach ($elements as $element) {
108 if (
109 !is_array($element) ||
110 !isset($element['name']) ||
111 !in_array($element['name'], self::ELEMENT_NAMES, true)
112 ) {
113 continue;
114 }
115
116 $elementAttrs = isset($element['attributes']) && is_array($element['attributes'])
117 ? $element['attributes']
118 : [];
119
120 if (isset($element['bindings']) && is_array($element['bindings']) && !empty($element['bindings'])) {
121 $elementAttrs['bindings'] = $element['bindings'];
122 }
123
124 $elementBlocks[] = $this->make_block(
125 'tableberg/' . $element['name'],
126 $elementAttrs,
127 []
128 );
129 }
130
131 return $this->make_block('tableberg/cell', $cellAttrs, $elementBlocks);
132 }
133
134 /**
135 * Positions covered by a rowSpan/colSpan anchor (excluding the anchor).
136 *
137 * @param array $cells
138 * @param int $rowsCount
139 * @param int $colsCount
140 * @return array<string, bool>
141 */
142 private function compute_covered_positions($cells, $rowsCount, $colsCount) {
143 $covered = [];
144
145 foreach ($cells as $key => $cell) {
146 if (!is_array($cell) || !isset($cell['span']) || !is_array($cell['span'])) {
147 continue;
148 }
149
150 $coords = explode(',', (string) $key);
151 if (count($coords) !== 2) {
152 continue;
153 }
154 $row = (int) $coords[0];
155 $col = (int) $coords[1];
156
157 $rowSpan = isset($cell['span']['rowSpan']) && is_numeric($cell['span']['rowSpan'])
158 ? max(1, (int) $cell['span']['rowSpan'])
159 : 1;
160 $colSpan = isset($cell['span']['colSpan']) && is_numeric($cell['span']['colSpan'])
161 ? max(1, (int) $cell['span']['colSpan'])
162 : 1;
163
164 for ($dr = 0; $dr < $rowSpan; $dr++) {
165 for ($dc = 0; $dc < $colSpan; $dc++) {
166 if ($dr === 0 && $dc === 0) {
167 continue;
168 }
169 $r = $row + $dr;
170 $c = $col + $dc;
171 if ($r >= $rowsCount || $c >= $colsCount) {
172 continue;
173 }
174 $covered["{$r},{$c}"] = true;
175 }
176 }
177 }
178
179 return $covered;
180 }
181
182 /**
183 * @param string $name
184 * @param array $attrs
185 * @param array $innerBlocks
186 * @return array
187 */
188 private function make_block($name, $attrs, $innerBlocks) {
189 return [
190 'blockName' => $name,
191 'attrs' => $attrs,
192 'innerBlocks' => $innerBlocks,
193 'innerHTML' => '',
194 'innerContent' => array_fill(0, count($innerBlocks), null),
195 ];
196 }
197 }
198