I have a OneToMany relationship between Article
and Image
entities. I created the Article's form like:
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('articleTitle','text',array('required' => false))
->add('articlePrice','number',array('required' => false))
->add('images', new ImageType())
;
}
....
}
And
class ImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', 'file',array('required' => false))
;
}
....
}
I have a problem in validating the file attribute. My goal is to return an error message when user chooses no file (at least one image should be associated to an Article). I tried by asserting the NotBlank
but it doesn't work.
<?php
....
use Symfony\Component\Validator\Constraints as Assert;
class Image
{
/**
* Image file
*
* @var File
* @Assert\NotBlank
*/
private $file;
....
}
I don't embed collections while creating my form, since project requirements oblige AJAX uploading for each image separately before submission of the whole form. In other words, a javascript event listener, bound to input change
event, creates the AJAX call which uploads the image after validation (ie. file is validated for size, extension, in controller). But when I send the overall form, only the other fields are validated and form is submitted even if no file is choosed (I see in headers all formData elements except the file one).
I want to notice that the form is rendered correcly when I inspect element in browser.
I spent a lot of time trying to resolve this issues but to no avail, your help is a rescue.
Edit: As requested by Mr Nawfal Serrar
The AJAX call is performed like:
$(':file').change(function(){
var file = this.files[0];
var url= $('.article-form').attr('data-iu-url');
var formData = new FormData($('form')[0]);
$.ajax({
url: url,
type: 'POST',
success: completeHandler,
data: formData,
});
});
url
contains the route image_upload
respecting following config:
image_upload:
pattern: /{id}/image_upload
defaults: { _controller: ShopManagementBundle:Image:uploads}
requirements: { _method: post|put }
Controller:
public function uploadsAction(Request $request, $id) {
if ($request->isMethod('POST')) {
$image = $request->files->get('articletype')['images']['file'];
$status='success';
$message='';
$uploadedURL='';
$the_id=0;
if (($image instanceof UploadedFile) && ($image->getError() == 0)) {
if ($image->getSize() < 50000000000) {
$originalName = $image->getClientOriginalName();
$name_array = explode('.', $originalName);
$extension = $name_array[sizeof($name_array) - 1];
$valid_file_types = array('jpeg', 'jpg', 'bmp', 'png', 'gif');
if (in_array(strtolower($extension), $valid_file_types)) {
$imagee= new Image();
$em = $this->getDoctrine()->getManager();
$imagee->setFile($image);
$imagee->setSubDir('hg');
$imagee->upload();
$entity = $em->getRepository('ShopManagementBundle:Article')->find($id);
$imagee->setAricle($entity);
$uploadedURL= $imagee->getUploadDir(). DIRECTORY_SEPARATOR . $imagee->getSubDir(). DIRECTORY_SEPARATOR . $image->getBasename();
$em->persist($entity);
$em->persist($imagee);
$em->flush();
$the_id=$imagee->getId();
} else {
$status = "fail";
$message = "extension problem";
}
} else {
$status = "fail";
$message = "Image size too big";
}
} else {
$status = "fail";
$message = "Error uploading";
}
return $this->render('ShopManagementBundle:Image:image_portion.html.twig', array(
'status' => $status,
'message' => $message,
'uploadedURL' => $uploadedURL,
'image_id'=>$the_id,
));
}
else
return new Response('RE try uploading');
}
As you can see I am not validation using isValid
in controller, I validate with if-else statements assuming that the file is already sent.
After all we said in comment zone, I would recommand you to use @Assert\File
for your file upload validation. It will prevent your if/else stack.
Since you told me you were attaching the uploaded files to an already existing Article, then using an embedded collection of forms would be the solution as I mentionned.
Since you'll retrieve the article and then create a form type with it, all the Images will be linked to it.
Add the count constraint on the Images list of your:
/**
* @Assert\Count(
* min = "1",
* minMessage = "You must upload at least one image",
* )
*/
private $images;
Since you will retrieve the Article which is already linked to uploaded Image instances, the validation will not throw an error. Otherwise, the user is trying to submit the form without images. The validation constraint will then make the form invalid.
There might be other little stuff to do to make it work, but it should help you to go ahead.
To properly handle file uploads better to follow this method :
http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html
Its the official one, then at the return of the upload method you check if there is no file return your error message else continue with your upload.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With