apiClient = $apiClient; $this->targetFolderId = $targetFolderId; } /** * Upload a file to DAM with metadata * Uses PHP's native multipart/form-data with CURLFile * * @param string $filePath Local file path * @param string $folderId Target folder ID (campaign folder) * @param array $metadata Optional metadata to set * @param array $sourceMetadata Full metadata structure from master asset to copy * @return array Upload result */ public function uploadFile($filePath, $folderId, $metadata = [], $sourceMetadata = null) { if (!file_exists($filePath)) { return [ 'success' => false, 'error' => 'File not found: ' . $filePath, 'filename' => basename($filePath) ]; } $filename = basename($filePath); $mimeType = mime_content_type($filePath); // Get base URL from ApiClient using reflection $baseUrlReflection = new ReflectionProperty($this->apiClient, 'baseUrl'); $baseUrlReflection->setAccessible(true); $baseUrl = $baseUrlReflection->getValue($this->apiClient); // Build URL $url = rtrim($baseUrl, '/') . '/v6/assets'; // Build minimal asset representation with just the name $minimalAssetRep = [ 'asset_resource' => [ 'asset' => [ 'name' => $filename, 'metadata' => [ 'metadata_element_list' => [ [ 'id' => 'ARTESIA.FIELD.ASSET NAME', 'type' => 'com.artesia.metadata.MetadataField', 'value' => [ 'cascading_domain_value' => false, 'domain_value' => false, 'value' => [ 'type' => 'string', 'value' => $filename ] ] ] ] ] ] ] ]; $postFields = [ 'asset_representation' => json_encode($minimalAssetRep), 'parent_folder_id' => $folderId, 'file' => new \CURLFile($filePath, $mimeType, $filename) ]; // Get authorization header $authHeader = ''; $headersReflection = new ReflectionProperty($this->apiClient, 'headers'); $headersReflection->setAccessible(true); $headers = $headersReflection->getValue($this->apiClient); if (isset($headers['Authorization'])) { $authHeader = $headers['Authorization']; } // Use curl directly for multipart upload $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $postFields, CURLOPT_HTTPHEADER => [ 'Accept: application/json', 'Authorization: ' . $authHeader ], CURLOPT_SSL_VERIFYPEER => false, CURLOPT_TIMEOUT => 120 ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { return [ 'success' => false, 'filename' => $filename, 'error' => 'CURL error: ' . $error, 'http_code' => 0 ]; } if ($httpCode == 201) { $responseData = json_decode($response, true); return [ 'success' => true, 'asset_id' => $responseData['asset_resource_list']['asset_resource'][0]['asset']['asset_id'] ?? null, 'filename' => $filename, 'http_code' => $httpCode ]; } // Extract detailed error message from API response $errorMsg = 'Upload failed'; if (!empty($response)) { $responseData = json_decode($response, true); if ($responseData && isset($responseData['exception_body'])) { $errorMsg = $responseData['exception_body']['message'] ?? $responseData['exception_body']['debug_message'] ?? 'API Error'; } elseif ($responseData && isset($responseData['error'])) { $errorMsg = $responseData['error']; } } return [ 'success' => false, 'filename' => $filename, 'error' => $errorMsg, 'http_code' => $httpCode, 'response_body' => $response ]; } /** * Build asset representation from source metadata (copying from master asset) * Updates filename but preserves all other metadata */ private function buildAssetRepresentationFromSource($filename, $sourceMetadata) { // Copy the entire metadata structure from the source $assetRep = [ 'asset_resource' => [ 'asset' => [ 'metadata' => $sourceMetadata, 'name' => $filename ] ] ]; // Update the ASSET NAME field if it exists in the metadata if (isset($sourceMetadata['metadata_element_list'])) { foreach ($sourceMetadata['metadata_element_list'] as &$category) { if (isset($category['metadata_element_list'])) { foreach ($category['metadata_element_list'] as &$field) { if ($field['id'] === 'ARTESIA.FIELD.ASSET NAME') { $field['value']['value']['value'] = $filename; } } } } } return $assetRep; } /** * Build asset representation for upload (fallback when no source metadata) */ private function buildAssetRepresentation($filename, $metadata = []) { $assetRep = [ 'asset_resource' => [ 'asset' => [ 'metadata' => [ 'metadata_element_list' => [] ] ] ] ]; // Add filename metadata $assetRep['asset_resource']['asset']['metadata']['metadata_element_list'][] = [ 'id' => 'ARTESIA.FIELD.ASSET NAME', 'type' => 'com.artesia.metadata.MetadataField', 'value' => [ 'cascading_domain_value' => false, 'domain_value' => false, 'value' => [ 'type' => 'string', 'value' => $filename ] ] ]; // Add custom metadata fields foreach ($metadata as $fieldId => $fieldValue) { $assetRep['asset_resource']['asset']['metadata']['metadata_element_list'][] = [ 'id' => $fieldId, 'type' => 'com.artesia.metadata.MetadataField', 'value' => [ 'cascading_domain_value' => false, 'domain_value' => false, 'value' => [ 'type' => 'string', 'value' => $fieldValue ] ] ]; } return $assetRep; } /** * Upload multiple files */ public function uploadMultipleFiles($files, $folderId, $metadata = []) { $results = [ 'total' => count($files), 'successful' => 0, 'failed' => 0, 'details' => [] ]; foreach ($files as $file) { $result = $this->uploadFile($file, $folderId, $metadata); if ($result['success']) { $results['successful']++; } else { $results['failed']++; } $results['details'][] = $result; } return $results; } }