vendor/dachcom-digital/formbuilder/src/FormBuilderBundle/Stream/AttachmentStream.php line 146

Open in your IDE?
  1. <?php
  2. namespace FormBuilderBundle\Stream;
  3. use Doctrine\DBAL\Query\QueryBuilder;
  4. use FormBuilderBundle\Event\OutputWorkflow\OutputWorkflowSignalEvent;
  5. use FormBuilderBundle\Event\OutputWorkflow\OutputWorkflowSignalsEvent;
  6. use FormBuilderBundle\Tool\FileLocator;
  7. use Pimcore\Logger;
  8. use Pimcore\Model\Asset;
  9. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  10. class AttachmentStream implements AttachmentStreamInterface
  11. {
  12.     protected const PACKAGE_IDENTIFIER 'formbuilder_package_identifier';
  13.     protected const SIGNAL_CLEAN_UP 'tmp_file_attachment_stream';
  14.     protected EventDispatcherInterface $eventDispatcher;
  15.     protected FileLocator $fileLocator;
  16.     public function __construct(EventDispatcherInterface $eventDispatcherFileLocator $fileLocator)
  17.     {
  18.         $this->eventDispatcher $eventDispatcher;
  19.         $this->fileLocator $fileLocator;
  20.     }
  21.     /**
  22.      * @return array<int, File>
  23.      */
  24.     public function createAttachmentLinks(array $datastring $formName): array
  25.     {
  26.         return $this->extractFiles($data);
  27.     }
  28.     public function createAttachmentAsset($data$fieldName$formName): ?Asset
  29.     {
  30.         if (!is_array($data)) {
  31.             return null;
  32.         }
  33.         $files $this->extractFiles($data);
  34.         if (count($files) === 0) {
  35.             return null;
  36.         }
  37.         $packageIdentifier '';
  38.         foreach ($files as $file) {
  39.             $packageIdentifier .= sprintf('%s-%s-%s-%s'filesize($file->getPath()), $file->getId(), $file->getPath(), $file->getName());
  40.         }
  41.         // create package identifier to check if we just in another channel
  42.         $packageIdentifier md5($packageIdentifier);
  43.         $formName \Pimcore\File::getValidFilename($formName);
  44.         $zipKey substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyz'), 05);
  45.         $zipFileName sprintf('%s-%s.zip'\Pimcore\File::getValidFilename($fieldName), $zipKey);
  46.         $zipPath sprintf('%s/%s'$this->fileLocator->getZipFolder(), $zipFileName);
  47.         $existingAssetPackage $this->findExistingAssetPackage($packageIdentifier$formName);
  48.         if ($existingAssetPackage instanceof Asset) {
  49.             return $existingAssetPackage;
  50.         }
  51.         try {
  52.             $zip = new \ZipArchive();
  53.             $zip->open($zipPath\ZipArchive::CREATE \ZipArchive::OVERWRITE);
  54.             foreach ($files as $file) {
  55.                 $zip->addFile($file->getPath(), $file->getName());
  56.             }
  57.             $zip->close();
  58.         } catch (\Exception $e) {
  59.             Logger::error(sprintf('Error while creating attachment zip (%s): %s'$zipPath$e->getMessage()));
  60.             return null;
  61.         }
  62.         if (!file_exists($zipPath)) {
  63.             Logger::error(sprintf('zip path does not exist (%s)'$zipPath));
  64.             return null;
  65.         }
  66.         $formDataParentFolder Asset\Folder::getByPath('/formdata');
  67.         if (!$formDataParentFolder instanceof Asset\Folder) {
  68.             Logger::error('parent folder does not exist (/formdata)!');
  69.             return null;
  70.         }
  71.         $formFolderExists Asset\Service::pathExists(sprintf('/formdata/%s'$formName));
  72.         if ($formFolderExists === false) {
  73.             $formDataFolder = new Asset\Folder();
  74.             $formDataFolder->setCreationDate(time());
  75.             $formDataFolder->setLocked(true);
  76.             $formDataFolder->setUserOwner(1);
  77.             $formDataFolder->setUserModification(0);
  78.             $formDataFolder->setParentId($formDataParentFolder->getId());
  79.             $formDataFolder->setFilename($formName);
  80.             try {
  81.                 $formDataFolder->save();
  82.             } catch (\Exception $e) {
  83.                 // fail silently.
  84.             }
  85.         } else {
  86.             $formDataFolder Asset\Folder::getByPath(sprintf('/formdata/%s'$formName));
  87.         }
  88.         if (!$formDataFolder instanceof Asset\Folder) {
  89.             Logger::error(sprintf('Error while creating form data folder (/formdata/%s)'$formName));
  90.             return null;
  91.         }
  92.         $assetData = [
  93.             'data'     => file_get_contents($zipPath),
  94.             'filename' => $zipFileName
  95.         ];
  96.         try {
  97.             $asset Asset::create($formDataFolder->getId(), $assetDatafalse);
  98.             $asset->setProperty(self::PACKAGE_IDENTIFIER'text'$packageIdentifierfalsefalse);
  99.             $asset->save();
  100.             if (file_exists($zipPath)) {
  101.                 unlink($zipPath);
  102.             }
  103.         } catch (\Exception $e) {
  104.             Logger::error(sprintf('Error while storing asset in pimcore (%s): %s'$zipPath$e->getMessage()));
  105.             return null;
  106.         }
  107.         return $asset;
  108.     }
  109.     /**
  110.      * @internal
  111.      */
  112.     public function cleanUp(OutputWorkflowSignalsEvent $signalsEvent): void
  113.     {
  114.         // keep assets if guard exception occurs: use may want to retry!
  115.         if ($signalsEvent->hasGuardException() === true) {
  116.             return;
  117.         }
  118.         foreach ($signalsEvent->getSignalsByName(self::SIGNAL_CLEAN_UP) as $signal) {
  119.             /** @var File $attachmentFile */
  120.             foreach ($signal->getData() as $attachmentFile) {
  121.                 $this->removeAttachmentFile($attachmentFile);
  122.             }
  123.         }
  124.     }
  125.     protected function removeAttachmentFile(File $attachmentFile): void
  126.     {
  127.         $targetFolder $this->fileLocator->getFilesFolder();
  128.         $target implode(DIRECTORY_SEPARATOR, [$targetFolder$attachmentFile->getId()]);
  129.         if (!is_dir($target)) {
  130.             return;
  131.         }
  132.         $this->fileLocator->removeDir($target);
  133.     }
  134.     /**
  135.      * @return array<int, File>
  136.      */
  137.     protected function extractFiles(array $data): array
  138.     {
  139.         $files = [];
  140.         foreach ($data as $fileData) {
  141.             $fileId = (string) $fileData['id'];
  142.             $fileDir sprintf('%s/%s'$this->fileLocator->getFilesFolder(), $fileId);
  143.             if (is_dir($fileDir)) {
  144.                 $dirFiles glob($fileDir '/*');
  145.                 if (count($dirFiles) === 1) {
  146.                     $files[] = new File($fileId$fileData['fileName'], $dirFiles[0]);
  147.                 }
  148.             }
  149.         }
  150.         // add signal for later clean up
  151.         $this->eventDispatcher->dispatch(
  152.             new OutputWorkflowSignalEvent(self::SIGNAL_CLEAN_UP$files),
  153.             OutputWorkflowSignalEvent::NAME
  154.         );
  155.         return $files;
  156.     }
  157.     protected function findExistingAssetPackage(string $packageIdentifierstring $formName): ?Asset
  158.     {
  159.         $assetListing = new Asset\Listing();
  160.         $assetListing->addConditionParam('`assets`.path = ?'sprintf('/formdata/%s/'$formName));
  161.         $assetListing->addConditionParam('`properties`.data = ?'$packageIdentifier);
  162.         $assetListing->setLimit(1);
  163.         $assetListing->onCreateQueryBuilder(function (QueryBuilder $queryBuilder) {
  164.             $queryBuilder->leftJoin(
  165.                 'assets',
  166.                 'properties',
  167.                 'properties',
  168.                 sprintf('properties.`cid` = assets.`id` AND properties.`ctype` = "asset" AND properties.`name` = "%s"'self::PACKAGE_IDENTIFIER)
  169.             );
  170.         });
  171.         $assets $assetListing->getAssets();
  172.         if (count($assets) === 0) {
  173.             return null;
  174.         }
  175.         return $assets[0];
  176.     }
  177. }