/** * File upload action */ public function uploadAction(Request $request) { $postRequest = $request->request; $files = $request->files; if (!$files->has('file') || !$files->get('file') instanceof UploadedFile || !$files->get('file')->isValid()) { $message = 'Error uploading the file'; throw new CmsException(null, $message); } $file = $files->get('file'); /* @var $file UploadedFile */ $em = $this->container->getDoctrine()->getManager(); $em->beginTransaction(); $repository = $em->getRepository(FileAbstraction::CN()); /* @var $repository FileNestedSetRepository */ $repository->getNestedSetRepository()->lock(); // Permission check $uploadPermissionCheckFolder = null; if ($postRequest->get('folder')) { $uploadPermissionCheckFolder = $this->getFolder('folder'); } else { $uploadPermissionCheckFolder = new SlashFolder(); } $this->checkActionPermission($uploadPermissionCheckFolder, FileAbstraction::PERMISSION_UPLOAD_NAME); try { // getting the folder to upload in $folder = null; if ($postRequest->get('folder')) { $folder = $this->getFolder('folder'); } // Will return the top folder created/found from folderPath string $firstSubFolder = null; // Create/get folder by path provided $folderPath = $postRequest->get('folderPath', ''); $folderPath = trim(str_replace('\\', '/', $folderPath), '/'); if (!empty($folderPath)) { $folderPathParts = explode('/', $folderPath); foreach ($folderPathParts as $part) { $folderFound = false; $children = null; if ($folder instanceof Folder) { $children = $folder->getChildren(); } elseif (is_null($folder)) { $children = $repository->getRootNodes(); } else { throw new \LogicException("Not supported folder type: " . gettype($folder) . ', class: ' . get_class($folder)); } foreach ($children as $child) { if ($child instanceof Folder) { $_name = $child->getTitle(); if (strcasecmp($_name, $part) === 0) { $folderFound = $child; break; } } } if ($folderFound) { $folder = $folderFound; } else { $folder = $this->createFolder($part, $folder); } if (empty($firstSubFolder)) { $firstSubFolder = $folder; } } } // checking for replace action if ($postRequest->has('file_id')) { $fileToReplace = $this->getFile('file_id'); $this->getFileStorage()->replaceFile($fileToReplace, $file); // close transaction and unlock the nested set $em->commit(); $repository->getNestedSetRepository()->unlock(); return new SupraJsonResponse($this->imageAndFileOutput($fileToReplace)); } $fileEntity = null; if ($this->getFileStorage()->isSupportedImageFormat($file->getPathname())) { $fileEntity = new Image(); } else { $fileEntity = new File(); } $em->persist($fileEntity); $fileEntity->setFileName($file->getClientOriginalName()); $fileEntity->setSize($file->getSize()); $fileEntity->setMimeType($file->getMimeType()); // additional jobs for images if ($fileEntity instanceof Image) { // store original size $imageProcessor = $this->getFileStorage()->getImageResizer(); $imageInfo = $imageProcessor->getImageInfo($file->getPathname()); $fileEntity->setWidth($imageInfo->getWidth()); $fileEntity->setHeight($imageInfo->getHeight()); } if (!empty($folder)) { // get parent folder private/public status $publicStatus = $folder->isPublic(); $fileEntity->setPublic($publicStatus); // Flush before nested set UPDATE $em->flush(); $folder->addChild($fileEntity); } // when "force" set to true, then we need to ignore duplicate // filename exception, so postfix will be added to filename if ($fileEntity instanceof File) { if ($postRequest->has('force') && $postRequest->filter('force', null, false, FILTER_VALIDATE_BOOLEAN)) { try { $this->getFileStorage()->validateFileUpload($fileEntity, $file['tmp_name']); } catch (DuplicateFileNameException $e) { $siblings = $fileEntity->getSiblings(); $existingNames = array(); foreach ($siblings as $siblingEntity) { if (!$siblingEntity->equals($fileEntity)) { $existingNames[] = $siblingEntity->getFileName(); } } $extension = $fileEntity->getExtension(); $fileNamePart = $fileEntity->getFileNameWithoutExtension(); $possibleName = null; // assume that 1000 iterations is enough, to create unique name // if not, well... duplicate file name exception will be thrown for ($i = 1; $i < 1000; $i++) { $possibleName = sprintf(self::DUPLICATE_NAME_PATTERN, $fileNamePart, $i, $extension); if (!in_array($possibleName, $existingNames)) { $fileEntity->setFileName($possibleName); break; } } } } } // when it is not enough available memory to complete Image resize/crop // file will be uploaded as simple File entity if ($fileEntity instanceof Image) { try { $this->getFileStorage()->validateFileUpload($fileEntity, $file->getPathname()); } catch (InsufficientSystemResources $e) { // Removing image $em->remove($fileEntity); $em->flush(); $fileEntity = new File(); $em->persist($fileEntity); $fileEntity->setFileName($file->getClientOriginalName()); $fileEntity->setSize($file->getSize()); $fileEntity->setMimeType($file->getType()); if (!is_null($folder)) { $publicStatus = $folder->isPublic(); $fileEntity->setPublic($publicStatus); // Flush before nested set UPDATE $em->flush(); $folder->addChild($fileEntity); } $message = "Amount of memory required for image [{$file['name']}] resizing exceeds available, it will be uploaded as a document"; $responseWarning = $message; } } $em->flush(); // trying to upload file $this->getFileStorage()->storeFileData($fileEntity, $file->getPathname()); } catch (\Exception $e) { try { // close transaction and unlock the nested set $em->flush(); $em->rollback(); $repository->getNestedSetRepository()->unlock(); } catch (\Exception $e) { $this->container->getLogger()->error("Failure on rollback/unlock: " . $e->__toString()); } throw new CmsException(null, $e->getMessage(), $e); } // close transaction and unlock the nested set $em->commit(); $repository->getNestedSetRepository()->unlock(); // generating output $output = $this->imageAndFileOutput($fileEntity); if (!empty($firstSubFolder)) { $firstSubFolderOutput = $this->entityToArray($firstSubFolder); $output['folder'] = $firstSubFolderOutput; } $response = new SupraJsonResponse(); $response->setData($output); if (isset($responseWarning)) { $response->setWarningMessage($responseWarning); } return $response; }