Search code examples
shopwareshopware6

Shopware 6 Cloning Media via PHP


I need to make backup of certain Media Files.

They are provided as array. Code make new UUID, copy properties and saves to database. This is working. The problem is I can't upload file to that database entry. I've got error: Object { status: "500", code: "CONTENT__MEDIA_DUPLICATED_FILE_NAME", title: "Internal Server Error"...

    function makeBackup(array $images, Context $context) :bool
    {
        foreach ($images as $i) {
            $uuid = Uuid::randomHex();
            $path = $this->urlGeneratorInterface->getRelativeMediaUrl($i);
            try {
                $this->publicFileSystem->read($path);
                $stream = $this->publicFileSystem->readStream($path);
                $metaData = stream_get_meta_data($stream);
                $oldFileNameWithPath = $metaData['uri'];
            }catch (UnableToReadFile $e){
                echo "[ERROR] File $path does not exists. Continuing.\n";
                continue;
            }

            $mimeType = mime_content_type($oldFileNameWithPath);
            $fileExtension = pathinfo($oldFileNameWithPath, PATHINFO_EXTENSION);
            $fileSize = filesize($oldFileNameWithPath);
            $fileName = pathinfo($oldFileNameWithPath, PATHINFO_FILENAME) . '_old.' . $fileExtension;
            $mediaFile = new MediaFile($fileName, $mimeType, $fileExtension, $fileSize);

            $backupMediaData = [
                'id' => $uuid,
                'fileName' => $i->getFileName()."_old",
                'mimeType' => $i->getMimeType(),
                'fileSize' => $i->getFileSize(),
                // 'mediaFolderId' => $media->getMediaFolderId(),
                'createdAt' => $i->getCreatedAt(),
                'updatedAt' => $i->getUpdatedAt(),
                'alt' => $i->getAlt(),
                'title' => $i->getTitle()."_old",
            ];
            $this->mediaRepository->create([$backupMediaData], $context);

           $this->fileSaver->persistFileToMedia(
                $mediaFile,
                pathinfo($oldFileNameWithPath, PATHINFO_FILENAME),
                $uuid,
                $context
            );
        }
        return true;
    }

I changed filename name, what's the problem?


Solution

  • When you use the original media related services, you'll find that the media entity is initially persisted without the fileName and other meta data info about the file. The persistFileToMedia method then checks whether a media entity with the file name you're trying to upload already exists. Since you're persisting one with that exact name just prior, you'll run into that exception.

    To make life a little bit easier, you can also use the clone method of the repository, to create a copy. You can define a behavior for the clone, where you can override certain properties. Finally you'll have to execute the clone command within a system-scoped context, as normally you wouldn't be allowed to directly write the fileName property, since that would normally be the job of the file saver abstraction, e.g. that method persistFileToMedia you're calling.

    Example:

    // to write fileName and other metadata directly, you need the system scope
    $newMediaId = $context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($oldMediaId): string {
        $behavior = new CloneBehavior([
            'mimeType' => null,
            'fileExtension' => null,
            'uploadedAt' => null,
            'fileName' => null,
            'fileSize' => null,
            'metaData' => null,
        ]);
    
        $newMediaId = Uuid::randomHex();
        $this->mediaRepository->clone($oldMediaId, $context, $newMediaId, $behavior);
    
        return $newMediaId;
    });
    
    $this->fileSaver->persistFileToMedia(
        $mediaFile,
        $originalFileName . '_old',
        $newMediaId,
        $context
    );