Symfony2 REST API
Goal: Upload images, use ImageResize to re-shape them and save them to a folder. Load them up and push to Mongo GridFS and then delete saved ones in folder.
Issue: Using unlink after flushing to mongodb triggers an error as if i have used unlink before:
Warning: file_get_contents(C:/Users/Nikola/Desktop/awesome/web\pictures\1366%20768_small.jpg): failed to open stream: No such file or directory
Note that if i don't use unlink everything goess fine.
GalleryController:
public function uploadAction(Request $request) {
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content- Type, Accept");
header ("Content-Type: application/json; charset=utf-8");
$response = new ResponseModel();
try {
// Did we receive any files ?
if( $request->files->count() === 0) {
throw new CustomErrorException("No files received");
}
$pathsToDelete = [];
$names = [];
$files = $request->files;
foreach ($files as $file) {
/* #var $file UploadedFile */
// Check mime type
if(!($file->getMimeType() == 'image/jpeg' || $file->getMimeType() == 'image/png')) {
throw new CustomErrorException("We are only accepting jpg and png files.");
}
//var_dump();
// Perform image operations and save them to a temp folder
// Create small image
$imageManipulator = new ImageResize($file->getRealPath());
$imageManipulator->resizeToHeight(200);
$imageManipulator->resizeToWidth(200);
$array = explode(".", $file->getClientOriginalName());
$name = $array[0];
$ext = $array[1];
$pathSmall = 'pictures'.DIRECTORY_SEPARATOR.$name.'_small.'.$ext;
$imageManipulator->save($pathSmall);
// Create medium image
$imageManipulator = new ImageResize($file->getRealPath());
$imageManipulator->resizeToHeight(600);
$imageManipulator->resizeToWidth(600);
$array = explode(".", $file->getClientOriginalName());
$name = $array[0];
$ext = $array[1];
$pathMedium = 'pictures'.DIRECTORY_SEPARATOR.$name.'_medium.'.$ext;
$imageManipulator->save($pathMedium);
// Create Large image
$imageManipulator = new ImageResize($file->getRealPath());
$imageManipulator->resizeToHeight(1024);
$imageManipulator->resizeToWidth(1024);
$array = explode(".", $file->getClientOriginalName());
$name = $array[0];
$ext = $array[1];
$pathLarge = 'pictures'.DIRECTORY_SEPARATOR.$name.'_large.'.$ext;
$imageManipulator->save($pathLarge);
// Get locator
$configDirectories = array($_SERVER['DOCUMENT_ROOT']);
$locator = new FileLocator($configDirectories);
// Create image
$img = new Image();
$img->setName($file->getClientOriginalName());
$img->setFileSmall($locator->locate($pathSmall));
$img->setFileMedium($locator->locate($pathMedium));
$img->setFileLarge($locator->locate($pathLarge));
// Save files to the database
$dm = $this->get('doctrine_mongodb')->getManager();
$dm->persist($img);
$dm->flush();
array_push($pathsToDelete, $locator->locate($pathSmall));
array_push($pathsToDelete, $locator->locate($pathMedium));
array_push($pathsToDelete, $locator->locate($pathLarge));
array_push($names, $file->getClientOriginalName());
}
// Delete files after persisting
foreach ($pathsToDelete as $p) {
unlink($p);
}
//Load files from db
foreach ($names as $n) {
$image = $this->get('doctrine_mongodb')->getRepository('BlueAwesomeBundle:Image')
->findOneBy(['name' => $n]);
//save them for testing
file_put_contents($n, $image->getFileSmall64());
}
$response->setData(['success' => true]);
}
catch(CustomErrorException $e) {
$response->setErr($e->getMessage());
}
return new JsonResponse($response);
}
Image
namespace Blue\AwesomeBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations\Date;
use Doctrine\ODM\MongoDB\Mapping\Annotations\File;
use Doctrine\ODM\MongoDB\Mapping\Annotations\Id;
use MongoId;
class Image
{
/**
* #var MongoId $id
*/
protected $id;
/**
* #var string $name
*/
protected $name;
/**
* #var file $file_small
*/
protected $file_small;
/**
* #var file $file_medium
*/
protected $file_medium;
/**
* #var file $file_large
*/
protected $file_large;
/**
* #var date $uploadDate
*/
protected $uploadDate;
/**
* #var string $mimeType
*/
protected $mimeType;
/**
* #var int $length
*/
protected $length;
/**
* #var int $chunkSize
*/
protected $chunkSize;
/**
* #var string $md5
*/
protected $md5;
/**
* Get id
*
* #return id $id
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return self
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string $name
*/
public function getName()
{
return $this->name;
}
/**
* Set fileSmall
*
* #param file $fileSmall
* #return self
*/
public function setFileSmall($fileSmall)
{
$this->file_small = $fileSmall;
return $this;
}
/**
* Get fileSmall
*
* #return file $fileSmall
*/
public function getFileSmall()
{
return $this->file_small;
}
/** Returns 64base representation
* #return string
*/
public function getFileSmall64() {
return $this->file_small->getBytes();
}
/**
* Set fileMedium
*
* #param file $fileMedium
* #return self
*/
public function setFileMedium($fileMedium)
{
$this->file_medium = $fileMedium;
return $this;
}
/**
* Get fileMedium
*
* #return file $fileMedium
*/
public function getFileMedium()
{
return $this->file_medium;
}
/** Returns 64base representation
* #return string
*/
public function getFileMedium64() {
return $this->file_medium->getBytes();
}
/**
* Set fileLarge
*
* #param file $fileLarge
* #return self
*/
public function setFileLarge($fileLarge)
{
$this->file_large = $fileLarge;
return $this;
}
/** Returns 64base representation
* #return string
*/
public function getFileLarge64() {
return $this->file_large->getBytes();
}
/**
* Get fileLarge
*
* #return file $fileLarge
*/
public function getFileLarge()
{
return $this->file_large;
}
/**
* Set uploadDate
*
* #param date $uploadDate
* #return self
*/
public function setUploadDate($uploadDate)
{
$this->uploadDate = $uploadDate;
return $this;
}
/**
* Get uploadDate
*
* #return date $uploadDate
*/
public function getUploadDate()
{
return $this->uploadDate;
}
/**
* Set mimeType
*
* #param string $mimeType
* #return self
*/
public function setMimeType($mimeType)
{
$this->mimeType = $mimeType;
return $this;
}
/**
* Get mimeType
*
* #return string $mimeType
*/
public function getMimeType()
{
return $this->mimeType;
}
/**
* Set length
*
* #param int $length
* #return self
*/
public function setLength($length)
{
$this->length = $length;
return $this;
}
/**
* Get length
*
* #return int $length
*/
public function getLength()
{
return $this->length;
}
/**
* Set chunkSize
*
* #param int $chunkSize
* #return self
*/
public function setChunkSize($chunkSize)
{
$this->chunkSize = $chunkSize;
return $this;
}
/**
* Get chunkSize
*
* #return int $chunkSize
*/
public function getChunkSize()
{
return $this->chunkSize;
}
/**
* Set md5
*
* #param string $md5
* #return self
*/
public function setMd5($md5)
{
$this->md5 = $md5;
return $this;
}
/**
* Get md5
*
* #return string $md5
*/
public function getMd5()
{
return $this->md5;
}
/**
* (PHP 5 >= 5.4.0)<br/>
* Specify data which should be serialized to JSON
* #link http://php.net/manual/en/jsonserializable.jsonserialize.php
* #return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
*/
function jsonSerialize()
{
return (object) [
'id' => $this->id,
'name' => $this->name,
'file' => $this->getFileSmall64(),
'mimeType' => $this->mimeType
];
}
}
Image.mongodb.yml
Blue\AwesomeBundle\Document\Image:
type: document
fields:
id:
id: true
name:
type: string
file_small:
type: file
file_medium:
type: file
file_large:
type: file
uploadDate:
type: date
mimeType:
type: string
length:
type: int
chunkSize:
type: string
md5:
type: string
SOLVED
The thing is that i tried to store multiple files in one image document. Well gridfs doesn't work that way, so the solution is to make an image Document that only stores 1 file. In my case i created 3 documents with different sizes with different subname field based on shared name field.
Related
Below code is working properly. It is for inserting new record into the database.
Entity:-(FileUpload.php)
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="FileUpload")
*/
class FileUpload
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string",unique=true)
*/
private $countryCode;
/**
* #ORM\Column(type = "string")
*/
private $fileData;
public function __construct(
string $countryCode,
string $fileData
) {
$this->countryCode = $countryCode;
$this->fileData = $fileData;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #param integer $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* Set countryCode
*
* #param string $countryCode
*
* #return FileUpload
*/
public function setCountryCode($countryCode)
{
$this->countryCode = $countryCode;
return $this;
}
/**
* Get countryCode
*
* #return string
*/
public function getCountryCode()
{
return $this->countryCode;
}
/**
* Set fileData
*
* #param string $fileData
*
* #return FileUpload
*/
public function setFileData($fileData)
{
$this->fileData = $fileData;
return $this;
}
/**
* Get fileData
*
* #return string
*/
public function getFileData()
{
return $this->fileData;
}
}
Controller:-
/**
* #Route("/file_upload")
* #Method({"POST"})
* #return JsonResponse
*/
public function addAction(SubscriptorService $subscriptorService, Request $request): JsonResponse
{
$countryCode = $request->request->get('countryCode');
$fileData = file_get_contents($_FILES['file']['tmp_name']);
$rst = $subscriptorService->fileUpload(
$countryCode,
$fileData
);
return new JsonResponse($rst);
}
}
Service:-
/**
* #param string $countryCode,
* #param string $fileData
*/
public function fileUpload(
string $countryCode,
string $fileData
): bool
{
$program = new FileUpload($countryCode, $fileData);
$this->em->persist($program);
$this->em->flush();
return true;
}
But now I need to check. If countryCode is alredy present then I need to update the fileData corresponding to that countryCode .Else we need to insert new record.
so I modified service method.
/**
* #param string $countryCode,
* #param string $fileData
*/
public function fileUpload(
string $countryCode,
string $fileData
): bool {
$program = $this
->em
->getRepository(FileUpload::class)->find($countryCode);
if ($program->getCountryCode() != null) {
$program->setFileData($program->getFileData());
$this->em->persist($program);
return true;
}
$program1 = new FileUpload($countryCode, $fileData);
$this->em->persist($program1);
$this->em->flush();
return true;
}
But now it is throwing error.
Call to a member function getCountryCode() on null (500 Internal Server Error)
I am not able to understand the issue. Could you please help me on the same.
Edit 1 :-
/**
* #param string $countryCode,
* #param string $fileData
*/
public function fileUpload(
string $countryCode,
string $fileData
): bool {
$program = $this->em->getRepository(FileUpload::class)->findByCountryCode($countryCode);
if ($program != null) {
$program->setFileData($fileData);
$this->em->persist($program);
return true;
}
$program1 = new FileUpload($countryCode, $fileData);
$this->em->persist($program1);
$this->em->flush();
return true;
}
I changed the code now getting below error.
Call to a member function setFileData() on array (500 Internal Server Error)
I uploaded my project from wamp to my host.
When I open my site, site shows :
(1/1) InvalidArgumentException
View [welcome] not found.
.....
in FileViewFinder.php line 137
FileViewFinder.php:
<?php
namespace Illuminate\View;
use InvalidArgumentException;
use Illuminate\Filesystem\Filesystem;
class FileViewFinder implements ViewFinderInterface
{
/**
* The filesystem instance.
*
* #var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* The array of active view paths.
*
* #var array
*/
protected $paths;
/**
* The array of views that have been located.
*
* #var array
*/
protected $views = [];
/**
* The namespace to file path hints.
*
* #var array
*/
protected $hints = [];
/**
* Register a view extension with the finder.
*
* #var array
*/
protected $extensions = ['blade.php', 'php', 'css'];
/**
* Create a new file view loader instance.
*
* #param \Illuminate\Filesystem\Filesystem $files
* #param array $paths
* #param array $extensions
* #return void
*/
public function __construct(Filesystem $files, array $paths, array $extensions = null)
{
$this->files = $files;
$this->paths = $paths;
if (isset($extensions)) {
$this->extensions = $extensions;
}
}
/**
* Get the fully qualified location of the view.
*
* #param string $name
* #return string
*/
public function find($name)
{
if (isset($this->views[$name])) {
return $this->views[$name];
}
if ($this->hasHintInformation($name = trim($name))) {
return $this->views[$name] = $this->findNamespacedView($name);
}
return $this->views[$name] = $this->findInPaths($name, $this->paths);
}
/**
* Get the path to a template with a named path.
*
* #param string $name
* #return string
*/
protected function findNamespacedView($name)
{
list($namespace, $view) = $this->parseNamespaceSegments($name);
return $this->findInPaths($view, $this->hints[$namespace]);
}
/**
* Get the segments of a template with a named path.
*
* #param string $name
* #return array
*
* #throws \InvalidArgumentException
*/
protected function parseNamespaceSegments($name)
{
$segments = explode(static::HINT_PATH_DELIMITER, $name);
if (count($segments) != 2) {
throw new InvalidArgumentException("View [$name] has an invalid name.");
}
if (! isset($this->hints[$segments[0]])) {
throw new InvalidArgumentException("No hint path defined for [{$segments[0]}].");
}
return $segments;
}
/**
* Find the given view in the list of paths.
*
* #param string $name
* #param array $paths
* #return string
*
* #throws \InvalidArgumentException
*/
protected function findInPaths($name, $paths)
{
foreach ((array) $paths as $path) {
foreach ($this->getPossibleViewFiles($name) as $file) {
if ($this->files->exists($viewPath = $path.'/'.$file)) {
return $viewPath;
}
}
}
throw new InvalidArgumentException("View [$name] not found.");
}
/**
* Get an array of possible view files.
*
* #param string $name
* #return array
*/
protected function getPossibleViewFiles($name)
{
return array_map(function ($extension) use ($name) {
return str_replace('.', '/', $name).'.'.$extension;
}, $this->extensions);
}
/**
* Add a location to the finder.
*
* #param string $location
* #return void
*/
public function addLocation($location)
{
$this->paths[] = $location;
}
/**
* Prepend a location to the finder.
*
* #param string $location
* #return void
*/
public function prependLocation($location)
{
array_unshift($this->paths, $location);
}
/**
* Add a namespace hint to the finder.
*
* #param string $namespace
* #param string|array $hints
* #return void
*/
public function addNamespace($namespace, $hints)
{
$hints = (array) $hints;
if (isset($this->hints[$namespace])) {
$hints = array_merge($this->hints[$namespace], $hints);
}
$this->hints[$namespace] = $hints;
}
/**
* Prepend a namespace hint to the finder.
*
* #param string $namespace
* #param string|array $hints
* #return void
*/
public function prependNamespace($namespace, $hints)
{
$hints = (array) $hints;
if (isset($this->hints[$namespace])) {
$hints = array_merge($hints, $this->hints[$namespace]);
}
$this->hints[$namespace] = $hints;
}
/**
* Replace the namespace hints for the given namespace.
*
* #param string $namespace
* #param string|array $hints
* #return void
*/
public function replaceNamespace($namespace, $hints)
{
$this->hints[$namespace] = (array) $hints;
}
/**
* Register an extension with the view finder.
*
* #param string $extension
* #return void
*/
public function addExtension($extension)
{
if (($index = array_search($extension, $this->extensions)) !== false) {
unset($this->extensions[$index]);
}
array_unshift($this->extensions, $extension);
}
/**
* Returns whether or not the view name has any hint information.
*
* #param string $name
* #return bool
*/
public function hasHintInformation($name)
{
return strpos($name, static::HINT_PATH_DELIMITER) > 0;
}
/**
* Flush the cache of located views.
*
* #return void
*/
public function flush()
{
$this->views = [];
}
/**
* Get the filesystem instance.
*
* #return \Illuminate\Filesystem\Filesystem
*/
public function getFilesystem()
{
return $this->files;
}
/**
* Get the active view paths.
*
* #return array
*/
public function getPaths()
{
return $this->paths;
}
/**
* Get the namespace to file path hints.
*
* #return array
*/
public function getHints()
{
return $this->hints;
}
/**
* Get registered extensions.
*
* #return array
*/
public function getExtensions()
{
return $this->extensions;
}
}
I tried several times but I could not solve this problem
I also edited the APP_URL in the .env file, but did not change
How can I fix it?
Try to clear your project cache: php artisan config:cache and php artisan cache:clear maybe the cache is looking for the file in a wrong place.
You can connect your host with vagrant ssh , after that go to your project location using CL and run this command: php artisan config:cache to regenerate the configuration.
Hope that helps you!
I have read questions concerning this topic and also seen responses that have been of importance thus far, but am currently experiencing some programming difficulties related to this same issue. I am trying to upload multiple files using the Symfony 3 framework and it's been a challenge really. I have the following code for doing this;
The first is the Form Type am using:
class ProductImageType extends AbstractType
{
/**
* Build the form
* #param None
* #return void
**/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', FileType::class, array('attr'=>array('class'=>'form-control'), 'multiple' => true));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'AppBundle\Entity\ProductImages',
)
);
}
public function getName()
{
return 'ProductImageType';
}
}
This is the Entity Am using:
class ProductImages
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="productSku", type="string", length=15, unique=true)
*/
private $productSku;
/**
* #var string $file
*
* #ORM\Column(name="file", type="string", length=255)
* #Assert\NotBlank(message="You must select at least one valid image file.")
*
*/
private $file;
/**
* #var int
*
* #ORM\Column(name="dateCreated", type="integer", nullable=true)
*/
private $dateCreated;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set productSku
*
* #param string $productSku
*
* #return productImages
*/
public function setProductSku($productSku)
{
$this->productSku = $productSku;
return $this;
}
/**
* Get productSku
*
* #return string
*/
public function getProductSku()
{
return $this->productSku;
}
/**
* Set images
*
* #param UploadedFile $file
*
* #return productImages
*/
public function setFile($file = null)
{
$this->file = $file;
return $this;
}
/**
* Get images
*
* #return string
*/
public function getFile()
{
return $this->file;
}
/**
* Set dateCreated
*
* #param integer $dateCreated
*
* #return productImages
*/
public function setDateCreated($dateCreated)
{
$this->dateCreated = $dateCreated;
return $this;
}
/**
* Get dateCreated
*
* #return int
*/
public function getDateCreated()
{
return $this->dateCreated;
}
}
And this is the controller am using to handle the file upload:
public function uploadAction(Request $request)
{
$files = $request->files->get('product_image');
$sku = $request->request->get('productSku');
$uploaded = false;
$message = null;
$count = 0;
$image_files = [];
$uploadDir = $this->getParameter('products_images_directory') . DIRECTORY_SEPARATOR . $sku . DIRECTORY_SEPARATOR;
$mimeTypes = array('image/jpeg','image/jpg','image/png','image/gif','image/bmp');
$doctrine = $this->getDoctrine()->getManager();
if(!empty($files))
{
foreach($files as $file => $v)
{
$filename[$count] = $sku . '_' . $count . '.' . $v[$count]->guessExtension();
$image_files[$count]['file'] = $filename[$count];
$image_files[$count]['file_size'] = $v[$count]->getClientSize();
Dump($image_files);die;
/**if(!is_dir($uploadDir) && !file_exists($uploadDir . $filename))
{
mkdir($uploadDir, 0775, TRUE);
if($value[$count]->move($uploadDir, $filename))
{
$productImages = new ProductImages();
$productImages->setProductSku($sku);
$productImages->setFile($filename[$i]);
$productImages->setDateCreated(strtotime(date('y-m-d h:i:s a')));
$doctrine->persist($productImages);
$doctrine->flush();
}
}
**/
$count++;
}
Dump($image_files);die('Action ended!');
if($count>1)
{
$uploaded = TRUE;
$message = "All Images have been uploaded & saved!!";
}
}
Dump($message);die;
return (new JsonResponse(
[
'uploaded'=>$uploaded,
'message'=>$message
]
));
}
I was going to use Dropzone.js to handle the front-end, i had to make sure everything works fine before integrating it. I discovered that when I try uploading multiple images using the foreach(...) only one of the images gets uploaded. on Dump(...) of the content of $request->request->get(...) i see the multiple files that were selected, but the foreach(...) only fetches the content of the first array not the second or third... I know the problem is within this condition, but i can't figure it out. Does someone have the sixth eye to assist, please?????
After much sleepless hours, i was able to finally get Symfony to work with dropzone.js for multiple (image) file uploads. This might be tweaked to work with other types of files of course:
My Entity:
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* productImages
*
* #ORM\Table(name="product_images")
* #ORM\Entity(repositoryClass="AppBundle\Repository\productImagesRepository")
*/
class ProductImages
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="productSku", type="string", length=15, unique=true)
*/
private $productSku;
/**
*
* #ORM\Column(name="files", type="string", length=255)
* #Assert\NotBlank(message="You must select at least one valid image
file.")
*
*/
private $files;
/**
* #var int
*
* #ORM\Column(name="dateCreated", type="integer", nullable=true)
*/
private $dateCreated;
/**
* Class Contructor
*
* #param array $options
* #return void
*/
public function __construct()
{}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set productSku
*
* #param string $productSku
*
* #return productImages
*/
public function setProductSku($productSku = NULL)
{
$this->productSku = $productSku;
return $this;
}
/**
* Get productSku
*
* #return string
*/
public function getProductSku()
{
return $this->productSku;
}
/**
* Set image Files
*
* #param String $files
*
* #return productImages
*/
public function setFiles($files = NULL)
{
$this->files = (string)$files;
return $this;
}
/**
* Get image Files
*
* #return string
*/
public function getFiles()
{
return $this->files;
}
/**
* Set dateCreated
*
* #param integer $dateCreated
*
* #return productImages
*/
public function setDateCreated($dateCreated)
{
$this->dateCreated = $dateCreated;
return $this;
}
/**
* Get dateCreated
*
* #return int
*/
public function getDateCreated()
{
return $this->dateCreated;
}
}
Form Type:
class ProductImageType extends AbstractType
{
/**
* Build the form
* #param None
* #return void
**/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('files', FileType::class, array('attr'=>array('class'=>'form-control'), 'multiple' => true));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'AppBundle\Entity\ProductImages',
)
);
}
public function getName()
{
return 'ProductImageType';
}
}
Controller Action:
/**
* Upload Product Image(s)
*
* #Route("/admin/products/upload", name="uploadProductImageRoute")
*
* #access public
* #param Request $request
* #return Object
**/
public function uploadInitAction(Request $request)
{
$files = $request->files->get('files');
$sku = $request->request->get('productSku');
$uploaded = false;
$message = null;
$count = $countValid = 0 ;
$mimeTypes = array('jpeg','jpg','png','gif','bmp');
if(!empty($files))
{
for($count; $count < count($files); $count++)
{
if(in_array($files[$count]->guessClientExtension(), $mimeTypes))
$countValid++;
}
if($countValid == count($files))
$uploaded = $this->uploadExec($sku, $files);
}
if($uploaded)
$message = "All Images have been uploaded & saved!!";
else
$message = "Selected File(s) weren't uploaded!!";
return $this->json(
[
'uploaded' => $uploaded,
'message' => $message
]
);
}
/**
* Performs Actual File Upload
*
* #param string $sku
* #param array $args
* #return Boolean
*
*/
private function uploadExec($sku, $args = array())
{
/**
* Make sure this is a new product without images saved yet
*/
if($this->hasImages($sku))return FALSE;
$count = 0;
$image_files = [];
$doctrine = $this->getDoctrine()->getManager();
$uploadDir = $this->getParameter('products_images_directory') . DIRECTORY_SEPARATOR . $sku . DIRECTORY_SEPARATOR;
if(!is_dir($uploadDir))
{
mkdir($uploadDir, 0775, TRUE);
}
if(!empty($args) && count($args) > 0)
{
for($count; $count < count($args); $count++)
{
$filename[$count] = $sku . '_' . $count . '.' . $args[$count]->guessClientExtension();
if(!file_exists($uploadDir . $filename[$count]))
{
if($args[$count]->move($uploadDir, $filename[$count]))
{
$image_files[$count]['file'] = $filename[$count];
$image_files[$count]['file_size'] = $args[$count]->getClientSize();
//$image_files[$count]['file_location'] = $uploadDir;
}
}
}
$jsonEncodeFiles = json_encode($image_files);
/*
* Persist Uploaded Image(s) to the Database
*/
$productImages = new ProductImages();
$productImages->setProductSku($sku);
$productImages->setFiles($jsonEncodeFiles);
$productImages->setDateCreated(strtotime(date('y-m-d h:i:s a')));
$doctrine->persist($productImages);
$doctrine->flush();
if( NULL != $productImages->getId() )return TRUE;
}
return FALSE;
}
Template:
{{ form_start(uploadForm, {'action':path('uploadProductImageRoute'), 'method' : 'POST', 'attr': {'id' : 'form-with-dropzone', 'class' : 'form-horizontal dropzone' }}) }}
<input type="hidden" name="productSku" value="{{ sku }}" />
<div class="row">
<div class="dropzone-previews"></div>
<div class="fallback">
{{ form_widget(uploadForm.files) }}
</div>
</div>
{{ form_end(uploadForm) }}
<div class="row no-margin-right no-margin-left">
<div class="form-group no-margin-right no-margin-left" style="margin-top: 30px;">
<div class="pull-right">
<button id="submit" type="submit" class="btn btn-sm btn-inverse"><i class="ace-icon typcn typcn-location-arrow-outline align-top bigger-115"></i> Upload Image(s)</button>
</div>
</div>
</div>
Javascript:
Dropzone.options.formWithDropzone = {
autoProcessQueue: false,
uploadMultiple: true,
paramName: "files",
parallelUploads: 10,
maxFiles: 10,
addRemoveLinks: true,
acceptedFiles: 'image/*',
init: function(){
var dropZone = this;
$('#submit').click(function(e){
e.preventDefault();
e.stopPropagation();
dropZone.processQueue();
});
dropZone.on("success", function(file, response) {
if(dropZone.getAcceptedFiles().length > 0){
$.gritter.add({
title : 'Upload Complete',
text : response.message + '\n\nA total of: ' + dropZone.getAcceptedFiles().length + ' images uploaded successfully!',
class_name : 'gritter-success'
})
}else{
$.gritter.add({
title : 'Upload Incomplete',
text : response.message,
class_name : 'gritter-error'
})
}
});
}
}
There was no need of making complex and unnecessary entity relationship mappings to get this to do what i wanted it to.
While working on this, i realized that using the getMimeType() method of the UploadedFile class to check the mimetype of the uploaded files(s) resulted in the error:
FileNotFoundException in MimeTypeGuesser.php line 123:
The file "F:\wamp2.5\tmp\php....tmp" does not exist
However, the error disappeard after i changed the method getMimeType() to guessClientExtension()
In future, i hope this will save someone a lot of time.
I'm trying to figure out how to do multiple file uploads but without luck. I have not been able to get too much info on this.. Maybe someone here will help me out? :D
Criteria:
I know that in my form type I'm supposed to use multiples for fields; but when I add it, it gives me the this error.
Catchable Fatal Error: Argument 1 passed to
PhotoGalleryBundle\Entity\Image::setFile() must be an instance of
Symfony\Component\HttpFoundation\File\UploadedFile, array given,
called in
/home/action/workspace/www/DecorInterior/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
on line 442 and defined
Image Entity
Here is my code in PHP:
<?php
namespace PhotoGalleryBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Image
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="PhotoGalleryBundle\Entity\ImageRepository")
* #ORM\HasLifecycleCallbacks
*/
class Image
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="imageCaptation", type="string", length=255)
* #Assert\NotBlank
*/
private $imageCaptation;
/**
* #var string
*
* #ORM\Column(name="imageName", type="string", length=255)
*/
private $imageName;
/**
* #var string
*
* #ORM\Column(name="imageFilePath", type="string", length=255, nullable=true)
*/
private $imageFilePath;
/**
* #var \DateTime
*
* #ORM\Column(name="imageUploadedDate", type="datetime")
* #Gedmo\Timestampable(on="create")
*/
private $imageUploadedDate;
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
/**
* #ORM\ManyToOne(targetEntity="Album", inversedBy="images")
* #ORM\JoinColumn(name="album", referencedColumnName="id")
*/
private $album;
private $temp;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set imageCaptation
*
* #param string $imageCaptation
* #return Image
*/
public function setImageCaptation($imageCaptation)
{
$this->imageCaptation = $imageCaptation;
return $this;
}
/**
* Get imageCaptation
*
* #return string
*/
public function getImageCaptation()
{
return $this->imageCaptation;
}
/**
* Set imageName
*
* #param string $imageName
* #return Image
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* Get imageName
*
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
/**
* Set imageFilePath
*
* #param string $imageFilePath
* #return Image
*/
public function setImageFilePath($imageFilePath)
{
$this->imageFilePath = $imageFilePath;
return $this;
}
/**
* Get imageFilePath
*
* #return string
*/
public function getImageFilePath()
{
return $this->imageFilePath;
}
/**
* Get imageUploadedDate
*
* #return \DateTime
*/
public function getImageUploadedDate()
{
return $this->imageUploadedDate;
}
/**
* Set file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null) {
$this->file = $file;
// check if we have an old image path
if (isset($this->imageFilePath)) {
// store the old name to delete after the update
$this->temp = $this->imageFilePath;
$this->imageFilePath = null;
} else {
$this->imageFilePath = 'initial';
}
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate
*/
public function preUpload() {
if (null !== $this->getFile()) {
// do whatever you want to generate a unique name
$fileName = sha1(uniqid(mt_rand(), true));
$this->imageFilePath = $fileName . '.' . $this->getFile()->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate
*/
public function upload() {
if (null === $this->getFile()) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->getFile()->move($this->getUploadRootDir(), $this->imageFilePath);
// check if we have an old image
if (isset($this->temp)) {
// delete the old image
unlink($this->getUploadRootDir() . '/' . $this->temp);
// clear the temp image path
$this->temp = null;
}
$this->imageFilePath = null;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload() {
$file = $this->getAbsolutePath();
if ($file) {
unlink($file);
}
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile() {
return $this->file;
}
public function getAbsolutePath() {
return null === $this->imageFilePath
? null
: $this->getUploadRootDir() . '/' . $this->imageFilePath;
}
public function getWebPath() {
return null === $this->imageFilePath
? null
: $this->getUploadDir() . '/' . $this->imageFilePath;
}
public function getUploadRootDir() {
// the absolute path where uploaded
// documents should be saved
return __DIR__.'/../../../web/' . $this->getUploadDir();
}
public function getUploadDir() {
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view
return 'uploads/images';
}
/**
* Set album
*
* #param \PhotoGalleryBundle\Entity\Album $album
* #return Image
*/
public function setAlbum(\PhotoGalleryBundle\Entity\Album $album = null)
{
$this->album = $album;
return $this;
}
/**
* Get album
*
* #return \PhotoGalleryBundle\Entity\Album
*/
public function getAlbum()
{
return $this->album;
}
}
ImageType:
<?php
namespace PhotoGalleryBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ImageType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('imageCaptation')
->add('imageName')
->add('file', 'file', array('multiple' => TRUE))
->add('album')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'PhotoGalleryBundle\Entity\Image'
));
}
/**
* #return string
*/
public function getName()
{
return 'photogallerybundle_image';
}
}
In this case the value will be an array of UploadedFile objects. Given that you have a type with multiple files yet only one caption, name, etc I assume you will want to refactor Image to support multiple image files. In this case the file property would be better known as files and setFiles should accept an array.
If however you want have one Image entity per file uploaded, consider implementing a collection instead.
Alternatively you could manually process the form in your action. For example:
public function uploadAction(Request $request)
{
foreach ($request->files as $uploadedFile) {
$uploadedFile = current($uploadedFile['file']);
// Build Image using each uploaded file
}
...
I want to embed a form (ImageType) into another (VideoFileType) in Symfony. My first form contains a file input. Basically, it's an image that will uploaded and then resized according to many presets already defined.
My second form will embed the ImageType form. The second form is a VideoFileType form which contains the ImageType form. Basically, the ImageType will act as a thumbnail for the video file. The VideoFileType will also contain a second file input to upload the videoFile and finally a select box to select the corresponding VideoPreset.
So to recap, the VideoFileType will embed an ImageType.
My class structure is similar. I have a VideoFile which has a Thumbnail attribute that is an Image class
When I show only the ImageType and upload an image, everything works perfectly fine.
ImageType:
class ImageType extends AbstractType
{
private $imageManager;
public function __construct(ImageManager $imageManager) {
$this->imageManager = $imageManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', 'file');
$builder->addEventListener(
FormEvents::POST_SUBMIT,
array($this, 'onPostSetData')
);
}
public function getDefaultOptions(array $options) {
return array('data_class' => 'OSC\MediaBundle\Entity\Image');
}
public function onPostSetData(FormEvent $event) {
$image = $event->getData();
$form = $event->getForm();
//We need here to update the video file with the new content
$image = $this->imageManager->uploadImage($image);
$event->setData($image);
}
public function getName()
{
return 'image';
}
}
VideoFileType
class VideoFileType extends AbstractType
{
public $container;
public $videoPresets = [];
public function __construct(Container $container) {
$this->container = $container;
$videoPresets = $container->getParameter('osc_media.video.presets');
foreach ($videoPresets as $key => $videoPreset) {
array_push($this->videoPresets, $key);
}
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('thumbnail', new ImageType($this->container->get('osc_media.manager.image')));
$builder->add('file', 'file');
$builder->add('videoPreset', 'choice', array(
'choices' => $this->videoPresets,
'multiple' => false,
'required' => true
));
$builder->addEventListener(
FormEvents::POST_SUBMIT,
array($this, 'onPostSetData')
);
$builder->add('save', 'submit');
}
public function onPostSetData(FormEvent $event) {
$videoFile = $event->getData();
$form = $event->getForm();
}
public function getDefaultOptions(array $options) {
return array('data_class' => 'OSC\MediaBundle\Entity\VideoFile');
}
public function getName()
{
return 'video_file';
}
}
VideoFile
class VideoFile
{
protected $file;
public function setfile(File $file = null)
{
$this->file = $file;
if ($file) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTime('now');
}
}
/**
* #return File
*/
public function getFile()
{
return $this->file;
}
public function __construct() {
$this->thumbnail = new Image();
}
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $name;
/**
* #var string
*/
private $filename;
/**
* #var integer
*/
private $position;
/**
* #var string
*/
private $extension;
/**
* #var integer
*/
private $size;
/**
* #var string
*/
private $videoPreset;
/**
* #var integer
*/
private $duration;
/**
* #var \DateTime
*/
private $createdAt;
/**
* #var \DateTime
*/
private $updatedAt;
/**
* #var string
*/
private $height;
/**
* #var string
*/
private $width;
/**
* #var \OSC\MediaBundle\Entity\Image
*/
private $thumbnail;
/**
* #var \OSC\MediaBundle\Entity\Video
*/
private $video;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return VideoFile
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set filename
*
* #param string $filename
* #return VideoFile
*/
public function setFilename($filename)
{
$this->filename = $filename;
return $this;
}
/**
* Get filename
*
* #return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* Set position
*
* #param integer $position
* #return VideoFile
*/
public function setPosition($position)
{
$this->position = $position;
return $this;
}
/**
* Get position
*
* #return integer
*/
public function getPosition()
{
return $this->position;
}
/**
* Set extension
*
* #param string $extension
* #return VideoFile
*/
public function setExtension($extension)
{
$this->extension = $extension;
return $this;
}
/**
* Get extension
*
* #return string
*/
public function getExtension()
{
return $this->extension;
}
/**
* Set size
*
* #param integer $size
* #return VideoFile
*/
public function setSize($size)
{
$this->size = $size;
return $this;
}
/**
* Get size
*
* #return integer
*/
public function getSize()
{
return $this->size;
}
/**
* Set videoPreset
*
* #param string $videoPreset
* #return VideoFile
*/
public function setVideoPreset($videoPreset)
{
$this->videoPreset = $videoPreset;
return $this;
}
/**
* Get videoPreset
*
* #return string
*/
public function getVideoPreset()
{
return $this->videoPreset;
}
/**
* Set duration
*
* #param integer $duration
* #return VideoFile
*/
public function setDuration($duration)
{
$this->duration = $duration;
return $this;
}
/**
* Get duration
*
* #return integer
*/
public function getDuration()
{
return $this->duration;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
* #return VideoFile
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
* #return VideoFile
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set height
*
* #param string $height
* #return VideoFile
*/
public function setHeight($height)
{
$this->height = $height;
return $this;
}
/**
* Get height
*
* #return string
*/
public function getHeight()
{
return $this->height;
}
/**
* Set width
*
* #param string $width
* #return VideoFile
*/
public function setWidth($width)
{
$this->width = $width;
return $this;
}
/**
* Get width
*
* #return string
*/
public function getWidth()
{
return $this->width;
}
/**
* Set thumbnail
*
* #param \OSC\MediaBundle\Entity\Image $thumbnail
* #return VideoFile
*/
public function setThumbnail(\OSC\MediaBundle\Entity\Image $thumbnail = null)
{
$this->thumbnail = $thumbnail;
return $this;
}
/**
* Get thumbnail
*
* #return \OSC\MediaBundle\Entity\Image
*/
public function getThumbnail()
{
return $this->thumbnail;
}
/**
* Set video
*
* #param \OSC\MediaBundle\Entity\Video $video
* #return VideoFile
*/
public function setVideo(\OSC\MediaBundle\Entity\Video $video = null)
{
$this->video = $video;
return $this;
}
/**
* Get video
*
* #return \OSC\MediaBundle\Entity\Video
*/
public function getVideo()
{
return $this->video;
}
}
Image Class
class Image
{
protected $file;
public function setfile(File $file = null)
{
$this->file = $file;
if ($file) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTime('now');
}
}
/**
* #return File
*/
public function getFile()
{
return $this->file;
}
/**
* #var integer
*/
private $id;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $imageFiles;
/**
* Constructor
*/
public function __construct()
{
$this->imageFiles = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add imageFiles
*
* #param \OSC\MediaBundle\Entity\ImageFile $imageFiles
* #return Image
*/
public function addImageFile(\OSC\MediaBundle\Entity\ImageFile $imageFiles)
{
$this->imageFiles[] = $imageFiles;
return $this;
}
/**
* Remove imageFiles
*
* #param \OSC\MediaBundle\Entity\ImageFile $imageFiles
*/
public function removeImageFile(\OSC\MediaBundle\Entity\ImageFile $imageFiles)
{
$this->imageFiles->removeElement($imageFiles);
}
/**
* Get imageFiles
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getImageFiles()
{
return $this->imageFiles;
}
}
ImageFile
class ImageFile
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $name;
/**
* #var string
*/
private $filename;
/**
* #var string
*/
private $extension;
/**
* #var string
*/
private $size;
/**
* #var string
*/
private $imagePreset;
/**
* #var \DateTime
*/
private $createdAt;
/**
* #var \DateTime
*/
private $updatedAt;
/**
* #var string
*/
private $height;
/**
* #var string
*/
private $width;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return ImageFile
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set filename
*
* #param string $filename
* #return ImageFile
*/
public function setFilename($filename)
{
$this->filename = $filename;
return $this;
}
/**
* Get filename
*
* #return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* Set extension
*
* #param string $extension
* #return ImageFile
*/
public function setExtension($extension)
{
$this->extension = $extension;
return $this;
}
/**
* Get extension
*
* #return string
*/
public function getExtension()
{
return $this->extension;
}
/**
* Set size
*
* #param string $size
* #return ImageFile
*/
public function setSize($size)
{
$this->size = $size;
return $this;
}
/**
* Get size
*
* #return string
*/
public function getSize()
{
return $this->size;
}
/**
* Set imagePreset
*
* #param string $imagePreset
* #return ImageFile
*/
public function setImagePreset($imagePreset)
{
$this->imagePreset = $imagePreset;
return $this;
}
/**
* Get imagePreset
*
* #return string
*/
public function getImagePreset()
{
return $this->imagePreset;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
* #return ImageFile
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
* #return ImageFile
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set height
*
* #param string $height
* #return ImageFile
*/
public function setHeight($height)
{
$this->height = $height;
return $this;
}
/**
* Get height
*
* #return string
*/
public function getHeight()
{
return $this->height;
}
/**
* Set width
*
* #param string $width
* #return ImageFile
*/
public function setWidth($width)
{
$this->width = $width;
return $this;
}
/**
* Get width
*
* #return string
*/
public function getWidth()
{
return $this->width;
}
}
However, when I try to create a VideoFileType form, I get the following error:
The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class OSC\MediaBundle\Entity\Image. You can avoid this error by setting the "data_class" option to "OSC\MediaBundle\Entity\Image" or by adding a view transformer that transforms an instance of class OSC\MediaBundle\Entity\Image to scalar, array or an instance of \ArrayAccess.
So, what I want, is the treatment of the ImageFileType (OnPostSetData) to be executed with the same success when embedded in VideoFileType as when used alone.
Then, after completion, I want the Image object to be inserted in the VideoFile as the thumbnail attribute. Afterwards, it should finish the treatment inside VideoFileType's OnPostSetData method.
If it's not feasible, I'll simply recreate ImageType's logic inside the VideoFileType and that is not a big deal. However, I feel that it could be nice if I could reuse the ImageFileType.
I'm not a 100% sure but try adding this function to your ImageTypeclass.
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
....
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'OSC\MediaBundle\Entity\Image'
));
}
And change the configuration for the thumbnail property inside buildForm in class VideoFileType.
$builder->add('thumbnail',
new ImageType($this->container->get('osc_media.manager.image')),
array(
'data_class' => 'OSC\MediaBundle\Entity\Image'
));
This is verry easy if you want to extend formtype,
just do like this:
Define your first form as a service
Extend your second form using getParent method
public function getParent()
{
return 'image';
}
doing like this you have the same fields in ur second form as in first
and you can add some more.