Database Changes:
- ALTER TABLE master_assets ADD COLUMN full_metadata JSONB
- Stores COMPLETE DAM asset metadata (no 5,000 char truncation)
- PostgreSQL JSONB type for efficient storage and querying
DatabaseClient Changes:
- Added full_metadata to INSERT and ON CONFLICT UPDATE
- Store complete json_encode($assetData) in full_metadata column
- Simplified description to just Box info (no metadata)
- Log metadata size when storing
- NO TRUNCATION - preserves all fields
Workflow Changes (workflow_v3.php):
- load_master_metadata: Read from full_metadata JSONB column
- upload_from_box: Read from full_metadata JSONB column
- Both endpoints now get COMPLETE master metadata
- Added logging for metadata size verification
Impact:
BEFORE: Only 5,000 chars stored (truncated)
AFTER: Full metadata stored (10,000+ chars, all fields preserved)
Next Step:
Re-download master assets to populate full_metadata for existing records.
New downloads will automatically use the new column.
🤖 Generated with Claude Code
289 lines
12 KiB
PHP
289 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
* DatabaseClient - Handles PostgreSQL database operations for asset tracking
|
|
* Stores master assets, tracking IDs, and Box file links
|
|
*/
|
|
class DatabaseClient
|
|
{
|
|
private $pdo;
|
|
|
|
public function __construct()
|
|
{
|
|
try {
|
|
$this->pdo = new PDO(
|
|
'pgsql:host=localhost;port=5433;dbname=ferrero_tracking',
|
|
'ferrero_user',
|
|
'ferrero_pass_2025'
|
|
);
|
|
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
error_log("DatabaseClient: Connected to PostgreSQL");
|
|
} catch (PDOException $e) {
|
|
error_log("DatabaseClient: Connection failed: " . $e->getMessage());
|
|
$this->pdo = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the PDO connection
|
|
* @return PDO|null
|
|
*/
|
|
public function getConnection()
|
|
{
|
|
return $this->pdo;
|
|
}
|
|
|
|
/**
|
|
* Store master asset in database
|
|
*/
|
|
public function storeMasterAsset($trackingId, $assetData, $boxFileId = null, $boxUrl = null, $uploadFolderId = null)
|
|
{
|
|
if (!$this->pdo) {
|
|
return ['success' => false, 'error' => 'Database not connected'];
|
|
}
|
|
|
|
try {
|
|
// Extract metadata from DAM asset
|
|
$metadata = $this->extractMetadataFields($assetData);
|
|
|
|
// Debug log what we extracted
|
|
error_log("DatabaseClient: Extracted metadata: " . json_encode($metadata));
|
|
error_log("DatabaseClient: Upload folder ID: " . ($uploadFolderId ?? 'NULL'));
|
|
|
|
// Insert using all available columns INCLUDING full_metadata
|
|
$stmt = $this->pdo->prepare("
|
|
INSERT INTO master_assets (
|
|
tracking_id,
|
|
opentext_id,
|
|
original_filename,
|
|
file_extension,
|
|
brand_code,
|
|
brand_name,
|
|
country_code,
|
|
language_code,
|
|
asset_type,
|
|
file_size_bytes,
|
|
mime_type,
|
|
width_px,
|
|
height_px,
|
|
upload_directory,
|
|
description,
|
|
full_metadata,
|
|
status
|
|
) VALUES (
|
|
:tracking_id,
|
|
:opentext_id,
|
|
:original_filename,
|
|
:file_extension,
|
|
:brand_code,
|
|
:brand_name,
|
|
:country_code,
|
|
:language_code,
|
|
:asset_type,
|
|
:file_size_bytes,
|
|
:mime_type,
|
|
:width_px,
|
|
:height_px,
|
|
:upload_directory,
|
|
:description,
|
|
:full_metadata,
|
|
:status
|
|
)
|
|
ON CONFLICT (tracking_id) DO UPDATE SET
|
|
upload_directory = EXCLUDED.upload_directory,
|
|
brand_code = EXCLUDED.brand_code,
|
|
country_code = EXCLUDED.country_code,
|
|
language_code = EXCLUDED.language_code,
|
|
width_px = EXCLUDED.width_px,
|
|
height_px = EXCLUDED.height_px,
|
|
description = EXCLUDED.description,
|
|
full_metadata = EXCLUDED.full_metadata
|
|
");
|
|
|
|
$pathInfo = pathinfo($assetData['name'] ?? 'unknown');
|
|
|
|
// Store FULL metadata JSON in dedicated column (NO TRUNCATION)
|
|
$metadataJson = json_encode($assetData);
|
|
|
|
// Keep description simple and readable (Box info only)
|
|
$description = "Box File ID: {$boxFileId}\nBox URL: {$boxUrl}\nDAM Asset ID: " . ($assetData['asset_id'] ?? 'Unknown');
|
|
|
|
error_log("DatabaseClient: Storing full metadata - size: " . strlen($metadataJson) . " bytes");
|
|
|
|
$stmt->execute([
|
|
':tracking_id' => $trackingId,
|
|
':opentext_id' => $assetData['asset_id'] ?? 'unknown',
|
|
':original_filename' => $pathInfo['filename'],
|
|
':file_extension' => '.' . ($pathInfo['extension'] ?? ''),
|
|
':brand_code' => $metadata['brand_code'],
|
|
':brand_name' => $metadata['brand_name'],
|
|
':country_code' => $metadata['country_code'],
|
|
':language_code' => $metadata['language_code'],
|
|
':asset_type' => $metadata['asset_type'],
|
|
':file_size_bytes' => $assetData['file_size'] ?? null,
|
|
':mime_type' => $assetData['mime_type'] ?? null,
|
|
':width_px' => $metadata['width_px'],
|
|
':height_px' => $metadata['height_px'],
|
|
':upload_directory' => $uploadFolderId, // Final Assets folder ID
|
|
':description' => $description,
|
|
':full_metadata' => $metadataJson, // COMPLETE metadata as JSONB
|
|
':status' => 'active'
|
|
]);
|
|
|
|
error_log("DatabaseClient: Stored asset " . $trackingId);
|
|
|
|
return ['success' => true, 'tracking_id' => $trackingId];
|
|
|
|
} catch (PDOException $e) {
|
|
error_log("DatabaseClient: Insert failed: " . $e->getMessage());
|
|
return ['success' => false, 'error' => $e->getMessage()];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extract metadata fields from DAM asset
|
|
*/
|
|
private function extractMetadataFields($assetData)
|
|
{
|
|
$fields = [
|
|
'brand_code' => null,
|
|
'brand_name' => null,
|
|
'country_code' => null,
|
|
'language_code' => null,
|
|
'asset_type' => null,
|
|
'width_px' => null,
|
|
'height_px' => null
|
|
];
|
|
|
|
// Debug: Log what keys exist in assetData
|
|
error_log("DatabaseClient: AssetData keys: " . implode(', ', array_keys($assetData)));
|
|
|
|
// Check if metadata field exists
|
|
if (isset($assetData['metadata']['metadata_element_list'])) {
|
|
error_log("DatabaseClient: Metadata field EXISTS with " . count($assetData['metadata']['metadata_element_list']) . " categories");
|
|
} else {
|
|
error_log("DatabaseClient: Metadata field MISSING or wrong structure");
|
|
}
|
|
|
|
// Extract width/height from master_content_info (not asset_content_info)
|
|
if (isset($assetData['master_content_info'])) {
|
|
$fields['width_px'] = $assetData['master_content_info']['width'] ?? null;
|
|
$fields['height_px'] = $assetData['master_content_info']['height'] ?? null;
|
|
error_log("DatabaseClient: Width/Height from master_content_info: " . ($fields['width_px'] ?? 'NULL') . 'x' . ($fields['height_px'] ?? 'NULL'));
|
|
}
|
|
// Fallback to asset_content_info if master_content_info doesn't exist
|
|
elseif (isset($assetData['asset_content_info']['master_content'])) {
|
|
$content = $assetData['asset_content_info']['master_content'];
|
|
$fields['width_px'] = $content['width'] ?? null;
|
|
$fields['height_px'] = $content['height'] ?? null;
|
|
error_log("DatabaseClient: Width/Height from asset_content_info: " . ($fields['width_px'] ?? 'NULL') . 'x' . ($fields['height_px'] ?? 'NULL'));
|
|
} else {
|
|
error_log("DatabaseClient: No content_info found for dimensions");
|
|
}
|
|
|
|
// Extract from metadata fields
|
|
if (isset($assetData['metadata']['metadata_element_list'])) {
|
|
foreach ($assetData['metadata']['metadata_element_list'] as $categoryIndex => $category) {
|
|
if (!isset($category['metadata_element_list'])) {
|
|
error_log("DatabaseClient: Category " . $categoryIndex . " has no metadata_element_list");
|
|
continue;
|
|
}
|
|
|
|
error_log("DatabaseClient: Category " . $categoryIndex . " has " . count($category['metadata_element_list']) . " elements");
|
|
|
|
foreach ($category['metadata_element_list'] as $element) {
|
|
$fieldId = $element['id'] ?? '';
|
|
|
|
// Extract SUB BRAND (exists in asset metadata)
|
|
if ($fieldId === 'FERRERO.FIELD.SUB BRAND') {
|
|
$fields['brand_name'] = $this->getFieldValue($element);
|
|
if ($fields['brand_name']) {
|
|
$fields['brand_code'] = strtoupper(substr($fields['brand_name'], 0, 3));
|
|
error_log("DatabaseClient: Extracted SUB BRAND: " . $fields['brand_name']);
|
|
}
|
|
}
|
|
|
|
// Extract MAIN LANGUAGES for language code
|
|
if ($fieldId === 'MAIN_LANGUAGES' || $fieldId === 'FERRERO.TABULAR.FIELD.MAIN LANGUAGES') {
|
|
// This is a tabular field - check for values
|
|
if (isset($element['values']) && is_array($element['values']) && count($element['values']) > 0) {
|
|
$langValue = $this->getFieldValue($element['values'][0]);
|
|
if ($langValue) {
|
|
$fields['language_code'] = strtolower(substr($langValue, 0, 2));
|
|
error_log("DatabaseClient: Extracted language: " . $fields['language_code']);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extract MKTG.ASSET TYPE
|
|
if ($fieldId === 'FERRERO.FIELD.MKTG.ASSET TYPE') {
|
|
$assetType = $this->getFieldValue($element);
|
|
if ($assetType) {
|
|
$fields['asset_type'] = strtoupper(substr($assetType, 0, 3)); // First 3 chars
|
|
error_log("DatabaseClient: Extracted asset type: " . $fields['asset_type']);
|
|
}
|
|
}
|
|
|
|
// Check for tabular fields (for language extraction)
|
|
if (isset($element['metadata_element_list']) && $fieldId === 'FERRERO.TABULAR.FIELD.MAIN LANGUAGES') {
|
|
foreach ($element['metadata_element_list'] as $tableField) {
|
|
// Extract language from tabular field
|
|
if (isset($tableField['values']) && is_array($tableField['values'])) {
|
|
foreach ($tableField['values'] as $langValue) {
|
|
$lang = $this->getFieldValue($langValue);
|
|
if ($lang) {
|
|
$fields['language_code'] = strtolower(substr($lang, 0, 2));
|
|
error_log("DatabaseClient: Extracted language from tabular: " . $fields['language_code']);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* Get field value from metadata element (handles both domain and regular values)
|
|
*/
|
|
private function getFieldValue($element)
|
|
{
|
|
$fieldId = $element['id'] ?? 'unknown';
|
|
|
|
// Handle domain values (with field_value)
|
|
if (isset($element['value']['value']['field_value']['value'])) {
|
|
$value = $element['value']['value']['field_value']['value'];
|
|
error_log("DatabaseClient: getFieldValue({$fieldId}) = {$value} (domain value)");
|
|
return $value;
|
|
}
|
|
|
|
// Handle regular string fields
|
|
if (isset($element['value']['value']['value'])) {
|
|
$value = $element['value']['value']['value'];
|
|
error_log("DatabaseClient: getFieldValue({$fieldId}) = {$value} (regular value)");
|
|
return $value;
|
|
}
|
|
|
|
// Log when we can't find a value
|
|
if (isset($element['value'])) {
|
|
error_log("DatabaseClient: getFieldValue({$fieldId}) - value exists but structure unknown");
|
|
error_log("DatabaseClient: Value structure: " . json_encode($element['value']));
|
|
} else {
|
|
error_log("DatabaseClient: getFieldValue({$fieldId}) - no value field at all");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check if database is available
|
|
*/
|
|
public function isConnected()
|
|
{
|
|
return $this->pdo !== null;
|
|
}
|
|
}
|