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

200 lines 6.4 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 // Everything the cell carries becomes a block attribute, not just
98 // the keys this file knows about — pro registers cell attributes of
99 // its own and they must survive the migration. `elements` is the one
100 // exception: it becomes the cell's inner blocks below.
101 $cellAttrs = is_array($cell) ? $cell : [];
102 unset($cellAttrs['elements']);
103
104 $elementBlocks = [];
105 $elements = isset($cell['elements']) && is_array($cell['elements'])
106 ? $cell['elements']
107 : [];
108
109 foreach ($elements as $element) {
110 if (
111 !is_array($element) ||
112 !isset($element['name']) ||
113 !in_array($element['name'], self::ELEMENT_NAMES, true)
114 ) {
115 continue;
116 }
117
118 $elementAttrs = isset($element['attributes']) && is_array($element['attributes'])
119 ? $element['attributes']
120 : [];
121
122 if (isset($element['bindings']) && is_array($element['bindings']) && !empty($element['bindings'])) {
123 $elementAttrs['bindings'] = $element['bindings'];
124 }
125
126 $elementBlocks[] = $this->make_block(
127 'tableberg/' . $element['name'],
128 $elementAttrs,
129 []
130 );
131 }
132
133 return $this->make_block('tableberg/cell', $cellAttrs, $elementBlocks);
134 }
135
136 /**
137 * Positions covered by a rowSpan/colSpan anchor (excluding the anchor).
138 *
139 * @param array $cells
140 * @param int $rowsCount
141 * @param int $colsCount
142 * @return array<string, bool>
143 */
144 private function compute_covered_positions($cells, $rowsCount, $colsCount) {
145 $covered = [];
146
147 foreach ($cells as $key => $cell) {
148 if (!is_array($cell) || !isset($cell['span']) || !is_array($cell['span'])) {
149 continue;
150 }
151
152 $coords = explode(',', (string) $key);
153 if (count($coords) !== 2) {
154 continue;
155 }
156 $row = (int) $coords[0];
157 $col = (int) $coords[1];
158
159 $rowSpan = isset($cell['span']['rowSpan']) && is_numeric($cell['span']['rowSpan'])
160 ? max(1, (int) $cell['span']['rowSpan'])
161 : 1;
162 $colSpan = isset($cell['span']['colSpan']) && is_numeric($cell['span']['colSpan'])
163 ? max(1, (int) $cell['span']['colSpan'])
164 : 1;
165
166 for ($dr = 0; $dr < $rowSpan; $dr++) {
167 for ($dc = 0; $dc < $colSpan; $dc++) {
168 if ($dr === 0 && $dc === 0) {
169 continue;
170 }
171 $r = $row + $dr;
172 $c = $col + $dc;
173 if ($r >= $rowsCount || $c >= $colsCount) {
174 continue;
175 }
176 $covered["{$r},{$c}"] = true;
177 }
178 }
179 }
180
181 return $covered;
182 }
183
184 /**
185 * @param string $name
186 * @param array $attrs
187 * @param array $innerBlocks
188 * @return array
189 */
190 private function make_block($name, $attrs, $innerBlocks) {
191 return [
192 'blockName' => $name,
193 'attrs' => $attrs,
194 'innerBlocks' => $innerBlocks,
195 'innerHTML' => '',
196 'innerContent' => array_fill(0, count($innerBlocks), null),
197 ];
198 }
199 }
200