Symfony 3 Несколько загрузок файлов

Я читал вопросы по этой теме, а также видел ответы, которые были важны до сих пор, но в настоящее время я испытываю некоторые трудности программирования, связанные с этой же проблемой. Я пытаюсь загрузить несколько файлов, используя платформу Symfony 3, и это действительно было проблемой. У меня есть следующий код для этого;
Первый тип формы я использую:

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';
}
}

Это сущность Am использует:

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;
}
}

И это контроллер, который я использую для обработки загрузки файла:

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
]
));

}

Я собирался использовать Dropzone.js для обработки внешнего интерфейса, я должен был убедиться, что все работает нормально, прежде чем интегрировать его. Я обнаружил, что когда я пытаюсь загрузить несколько изображений, используя foreach(...) загружается только одно из изображений. на Dump(...) содержания $request->request->get(...) я вижу несколько файлов, которые были выбраны, но foreach(...) только выбирает содержимое первого массива, а не второго или третьего … Я знаю, что проблема в этом условии, но я не могу понять это. У кого-нибудь есть шестой глаз, чтобы помочь, пожалуйста?

0

Решение

После долгих бессонных часов я смог наконец заставить Symfony работать с dropzone.js для нескольких загрузок (изображений) файлов. Конечно, это может быть настроено для работы с другими типами файлов:

Моя сущность:

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;
}
}

Тип формы:

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';
}

}

Действие контроллера:

/**
* 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;
}

Шаблон:

{{ 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>&nbsp;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'
})
}
});
}
}

Не было необходимости делать сложные и ненужные сопоставления отношений сущностей, чтобы заставить это делать то, что я хотел.
Работая над этим, я понял, что используя getMimeType() метод UploadedFile Класс для проверки MIME-типа загруженных файлов (ы) привел к ошибке:
FileNotFoundException in MimeTypeGuesser.php line 123:
The file "F:\wamp2.5\tmp\php....tmp" does not exist

Однако ошибка исчезает после того, как я изменил метод getMimeType() в guessClientExtension()

В будущем, я надеюсь, это сэкономит кому-то много времени.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector