Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

notBlank constraint not working for File input - Form with OneToMany relationship Symfony2

Tags:

forms

symfony

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 changeevent, 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.

like image 446
Adib Aroui Avatar asked Mar 18 '15 08:03

Adib Aroui


2 Answers

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.

like image 111
Grégory Elhaimer Avatar answered Nov 17 '22 02:11

Grégory Elhaimer


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.

like image 26
Nawfal Serrar Avatar answered Nov 17 '22 01:11

Nawfal Serrar