fileStorageManager = $fileStorageManager; } public function injectFileManager(FileManager $fileManager): void { $this->fileManager = $fileManager; } /** * Duplicate a document entity including its attachment file * * This creates a complete copy of a document with: * - All entity fields (name, description, etc.) * - Physical attachment file copied to new location * - Recalculated blake3hash * - Reset fileStatus to 'new' * * @param string $documentId Source document ID to duplicate * @return Entity New CDokumente entity * @throws NotFound If document doesn't exist * @throws Forbidden If no read access * @throws BadRequest If document has no attachment */ public function duplicateDocument(string $documentId): Entity { // 1. Load source document $sourceDoc = $this->entityManager->getEntity('CDokumente', $documentId); if (!$sourceDoc) { throw new NotFound('Document not found'); } // 2. ACL Check if (!$this->acl->check($sourceDoc, 'read')) { throw new Forbidden('No read access to document'); } // 3. Get source attachment $sourceAttachmentId = $sourceDoc->get('dokumentId'); if (!$sourceAttachmentId) { throw new BadRequest('Document has no attachment'); } $sourceAttachment = $this->entityManager->getEntity('Attachment', $sourceAttachmentId); if (!$sourceAttachment) { throw new BadRequest('Source attachment not found'); } try { // 4. Copy attachment file physically $newAttachment = $this->duplicateAttachment($sourceAttachment); // 5. Create new document entity $newDoc = $this->entityManager->getEntity('CDokumente'); // Copy all relevant fields $newDoc->set([ 'name' => $sourceDoc->get('name'), 'description' => $sourceDoc->get('description'), 'dokumentId' => $newAttachment->getId(), 'assignedUserId' => $sourceDoc->get('assignedUserId'), 'fileStatus' => 'new' // Reset to 'new' ]); // Copy teams $teamsIds = $sourceDoc->getLinkMultipleIdList('teams'); if (!empty($teamsIds)) { $newDoc->setLinkMultipleIdList('teams', $teamsIds); } // Copy preview if exists if ($sourceDoc->get('previewId')) { $sourcePreview = $this->entityManager->getEntity('Attachment', $sourceDoc->get('previewId')); if ($sourcePreview) { $newPreview = $this->duplicateAttachment($sourcePreview); $newDoc->set('previewId', $newPreview->getId()); } } // 6. Save new document (this will trigger blake3hash calculation via Hook) $this->entityManager->saveEntity($newDoc); // 7. Return new document return $newDoc; } catch (\Exception $e) { $GLOBALS['log']->error('CDokumente duplicateDocument Error: ' . $e->getMessage()); throw new \RuntimeException('Failed to duplicate document: ' . $e->getMessage()); } } /** * Duplicate an attachment entity including physical file * * @param Entity $sourceAttachment Source attachment to duplicate * @return Entity New attachment entity */ private function duplicateAttachment(Entity $sourceAttachment): Entity { // 1. Get source file path $sourceFilePath = $this->fileStorageManager->getLocalFilePath($sourceAttachment); if (!file_exists($sourceFilePath)) { throw new \RuntimeException('Source file not found: ' . $sourceFilePath); } // 2. Read source file content $fileContent = $this->fileManager->getContents($sourceFilePath); // 3. Create new attachment entity $newAttachment = $this->entityManager->getEntity('Attachment'); $newAttachment->set([ 'name' => $sourceAttachment->get('name'), 'type' => $sourceAttachment->get('type'), 'size' => $sourceAttachment->get('size'), 'role' => $sourceAttachment->get('role') ?? 'Attachment', 'storageFilePath' => null // Will be set by putContents ]); $this->entityManager->saveEntity($newAttachment); // 4. Write file content to new location $this->fileStorageManager->putContents($newAttachment, $fileContent); // 5. Return new attachment return $newAttachment; } }