This commit is contained in:
2026-01-20 01:44:49 +01:00
parent 3d559924a9
commit 8e6248cea1
7 changed files with 158 additions and 76 deletions

View File

@@ -342,6 +342,19 @@ class ApiKernel
return $this->tableMap['content_sections'] ?? $this->lookupTableName('content_sections', 'emailtemplate_content_sections');
}
private function resolveContentItemColumns(string $table): array
{
$cols = $this->tableColumns($table);
return [
'category' => $this->firstExisting($cols, ['category', 'cat']),
'html' => $this->firstExisting($cols, ['html', 'html_content', 'body', 'markup', 'content']),
'json' => $this->firstExisting($cols, ['json_content']),
'editor' => $this->firstExisting($cols, ['editor_type', 'editor']),
'craft' => $this->firstExisting($cols, ['craft_json', 'craft_content', 'craft_data']),
'settings' => $this->firstExisting($cols, ['settings_json', 'settings']),
];
}
private function useUnifiedContent(): bool
{
return $this->tableExists($this->contentItemsTable()) && $this->tableExists($this->contentSectionsTable());
@@ -514,6 +527,10 @@ class ApiKernel
if (!$this->tableExists($itemsTable) || !$this->tableExists($sectionsTable)) {
$this->fail('Content tables not available', null, 500);
}
$itemCols = $this->resolveContentItemColumns($itemsTable);
$catCol = $itemCols['category'];
$htmlCol = $itemCols['html'];
$jsonCol = $itemCols['json'];
$section = $fixedSection ?: $this->resolveSectionFromInput($customerId);
$q = trim((string)$this->val($this->in, 'q', ''));
@@ -527,7 +544,11 @@ class ApiKernel
$params[':sid'] = (int)$section['id'];
}
if ($q !== '') {
$where .= " AND (i.`name` LIKE :q OR i.`category` LIKE :q) ";
$where .= " AND (i.`name` LIKE :q";
if ($catCol) {
$where .= " OR i.`$catCol` LIKE :q";
}
$where .= ") ";
$params[':q'] = '%' . $q . '%';
}
@@ -550,7 +571,7 @@ class ApiKernel
'id' => $r['id'] ?? null,
'name' => $r['name'] ?? null,
'api_name' => $r['api_name'] ?? null,
'category' => $r['category'] ?? null,
'category' => $catCol ? ($r[$catCol] ?? null) : null,
'section_id' => $r['section_id'] ?? null,
'section_name' => $r['section_name'] ?? null,
'section_slug' => $r['section_slug'] ?? null,
@@ -559,8 +580,8 @@ class ApiKernel
'updated_at' => $r['updated_at'] ?? null,
'created_at' => $r['created_at'] ?? null,
];
if (array_key_exists('html', $r)) $item['html'] = (string)($r['html'] ?? '');
if (array_key_exists('json_content', $r)) $item['content'] = $r['json_content'];
if ($htmlCol && array_key_exists($htmlCol, $r)) $item['html'] = (string)($r[$htmlCol] ?? '');
if ($jsonCol && array_key_exists($jsonCol, $r)) $item['content'] = $r[$jsonCol];
$out[] = $item;
}
@@ -588,6 +609,11 @@ class ApiKernel
if (!$this->tableExists($itemsTable) || !$this->tableExists($sectionsTable)) {
$this->fail('Content tables not available', null, 500);
}
$itemCols = $this->resolveContentItemColumns($itemsTable);
$htmlCol = $itemCols['html'];
$jsonCol = $itemCols['json'];
$craftCol = $itemCols['craft'];
$editorCol = $itemCols['editor'];
$section = $fixedSection ?: $this->resolveSectionFromInput($customerId);
$params = [':cid' => $customerId, ':id' => $id];
@@ -608,8 +634,8 @@ class ApiKernel
$row = $stmt->fetch();
if (!$row) $this->fail('Not found', ['id' => $id], 404);
$html = (string)($row['html'] ?? '');
$json = $row['json_content'] ?? null;
$html = $htmlCol ? (string)($row[$htmlCol] ?? '') : '';
$json = $jsonCol ? ($row[$jsonCol] ?? null) : null;
$gjsComponents = [];
if ($json !== null) {
$decoded = json_decode((string)$json, true);
@@ -635,8 +661,8 @@ class ApiKernel
'html' => $html,
'content' => $json,
'gjs_components' => $gjsComponents,
'editor_type' => $row['editor_type'] ?? null,
'craft_json' => $row['craft_json'] ?? null,
'editor_type' => $editorCol ? ($row[$editorCol] ?? null) : null,
'craft_json' => $craftCol ? ($row[$craftCol] ?? null) : null,
]);
}
@@ -650,6 +676,13 @@ class ApiKernel
if (!$this->tableExists($itemsTable)) {
$this->fail('Content table not available', null, 500);
}
$itemCols = $this->resolveContentItemColumns($itemsTable);
$catCol = $itemCols['category'];
$htmlCol = $itemCols['html'];
$jsonCol = $itemCols['json'];
$editorCol = $itemCols['editor'];
$craftCol = $itemCols['craft'];
$settingsCol = $itemCols['settings'];
$name = trim((string)$this->val($this->in, ['name', 'title'], ''));
if ($name === '') $this->fail('name required', null, 422);
@@ -683,22 +716,27 @@ class ApiKernel
'name' => $name,
'api_name' => $apiName,
];
if ($category !== null) $data['category'] = (string)$category;
if ($editorType !== '') $data['editor_type'] = $editorType;
if ($craftJson !== null) $data['craft_json'] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson);
if ($settings !== null) $data['settings_json'] = is_string($settings) ? $settings : $this->encodeJson($settings);
if ($category !== null && $catCol) $data[$catCol] = (string)$category;
if ($editorType !== '' && $editorCol) $data[$editorCol] = $editorType;
if ($craftJson !== null && $craftCol) $data[$craftCol] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson);
if ($settings !== null && $settingsCol) $data[$settingsCol] = is_string($settings) ? $settings : $this->encodeJson($settings);
if ($json !== null) {
if (!$jsonCol) $this->fail('json_content column missing', null, 500);
$components = is_string($json) ? json_decode($json, true) : $json;
if (is_array($components)) {
$components = $this->cleanReferenceComponents($components);
$data['json_content'] = $this->encodeJson($components);
$data[$jsonCol] = $this->encodeJson($components);
} else {
$data['json_content'] = is_string($json) ? $json : '';
$data[$jsonCol] = is_string($json) ? $json : '';
}
if ($html !== null) {
if (!$htmlCol) $this->fail('html column missing', null, 500);
$data[$htmlCol] = (string)$html;
}
if ($html !== null) $data['html'] = (string)$html;
} elseif ($html !== null) {
$data['html'] = (string)$html;
if (!$htmlCol) $this->fail('html column missing', null, 500);
$data[$htmlCol] = (string)$html;
}
$columns = array_keys($data);
@@ -721,6 +759,13 @@ class ApiKernel
if (!$this->tableExists($itemsTable)) {
$this->fail('Content table not available', null, 500);
}
$itemCols = $this->resolveContentItemColumns($itemsTable);
$catCol = $itemCols['category'];
$htmlCol = $itemCols['html'];
$jsonCol = $itemCols['json'];
$editorCol = $itemCols['editor'];
$craftCol = $itemCols['craft'];
$settingsCol = $itemCols['settings'];
$id = $this->pullId($this->in);
if ($id === null || $id === '') $this->fail('id required', null, 422);
@@ -741,7 +786,7 @@ class ApiKernel
if ($name !== null) $data['name'] = (string)$name;
$category = $this->val($this->in, ['category', 'cat'], null);
if ($category !== null) $data['category'] = (string)$category;
if ($category !== null && $catCol) $data[$catCol] = (string)$category;
$apiRaw = $this->val($this->in, ['api_name', 'apiName', 'api'], null);
$apiName = $apiRaw !== null ? $this->normalizeApiName((string)$apiRaw) : null;
@@ -769,24 +814,29 @@ class ApiKernel
$html = $this->val($this->in, ['html', 'body', 'markup', 'content'], null);
$json = $this->val($this->in, ['content_json', 'json', 'structure_json'], null);
if ($json !== null) {
if (!$jsonCol) $this->fail('json_content column missing', null, 500);
$components = is_string($json) ? json_decode($json, true) : $json;
if (is_array($components)) {
$components = $this->cleanReferenceComponents($components);
$data['json_content'] = $this->encodeJson($components);
$data[$jsonCol] = $this->encodeJson($components);
} else {
$data['json_content'] = is_string($json) ? $json : '';
$data[$jsonCol] = is_string($json) ? $json : '';
}
if ($html !== null) {
if (!$htmlCol) $this->fail('html column missing', null, 500);
$data[$htmlCol] = (string)$html;
}
if ($html !== null) $data['html'] = (string)$html;
} elseif ($html !== null) {
$data['html'] = (string)$html;
if (!$htmlCol) $this->fail('html column missing', null, 500);
$data[$htmlCol] = (string)$html;
}
$editorType = $this->val($this->in, ['editor_type', 'editor'], null);
if ($editorType !== null) $data['editor_type'] = strtolower(trim((string)$editorType));
if ($editorType !== null && $editorCol) $data[$editorCol] = strtolower(trim((string)$editorType));
$craftJson = $this->val($this->in, ['craft_json', 'craft_content', 'craft_data'], null);
if ($craftJson !== null) $data['craft_json'] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson);
if ($craftJson !== null && $craftCol) $data[$craftCol] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson);
$settings = $this->val($this->in, ['settings_json', 'settings'], null);
if ($settings !== null) $data['settings_json'] = is_string($settings) ? $settings : $this->encodeJson($settings);
if ($settings !== null && $settingsCol) $data[$settingsCol] = is_string($settings) ? $settings : $this->encodeJson($settings);
if (!$data) {
$this->respond(['ok' => true, 'kind' => 'content', 'id' => $id, 'updated' => true]);
@@ -2313,7 +2363,17 @@ class ApiKernel
return null;
}
$itemsTable = $this->contentItemsTable();
$sql = "SELECT `html`,`json_content` FROM `$itemsTable` WHERE `customer_id` = :cid AND `section_id` = :sid AND `id` = :id LIMIT 1";
$itemCols = $this->resolveContentItemColumns($itemsTable);
$htmlCol = $itemCols['html'];
$jsonCol = $itemCols['json'];
if (!$htmlCol && !$jsonCol) {
$cache[$cacheKey] = null;
return null;
}
$selectCols = [];
if ($htmlCol) $selectCols[] = "`$htmlCol`";
if ($jsonCol) $selectCols[] = "`$jsonCol`";
$sql = "SELECT " . implode(',', $selectCols) . " FROM `$itemsTable` WHERE `customer_id` = :cid AND `section_id` = :sid AND `id` = :id LIMIT 1";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':cid' => $customerId, ':sid' => (int)$section['id'], ':id' => $id]);
$row = $stmt->fetch();
@@ -2321,7 +2381,7 @@ class ApiKernel
$cache[$cacheKey] = null;
return null;
}
$html = (string)($row['html'] ?? '');
$html = $htmlCol ? (string)($row[$htmlCol] ?? '') : '';
} else {
if (!$kindKey) return null;
$table = $this->tableMap[$kindKey] ?? null;