Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem uploading file #15

Closed
madarco opened this issue Feb 13, 2012 · 11 comments
Closed

Problem uploading file #15

madarco opened this issue Feb 13, 2012 · 11 comments

Comments

@madarco
Copy link

madarco commented Feb 13, 2012

I have the following Entity (not Doctrine Entity, just a plain class):

class RegistrationEntity {
    private $photo;
    ...

    public function setPhoto($photo) {
        if($photo instanceof UploadedFile) {
            $this->photo = $photo->move('/tmp', 'foo.jpg')->getPathname();
        }
        else {
            $this->photo = $photo;
        }
    }
 }

With my action I'm trying to upload the photo on step 2 (of 3):

 public function accountantAction() {
    $values = new RegistrationEntity(); 

    //Manage multi-step form:
    $flow = $this->get('longtale.form.flow.registrationFlow'); // must match the flow's service id
    $flow->bind($values);

    $form = $flow->createForm($values);

    if ($flow->isValid($form)) {
              $flow->saveCurrentStepData();

              if ($flow->nextStep()) {

              // render form for next step
              return array(
                  'form' => $flow->createForm($values)->createView(),
                  'flow' => $flow,
             );
         }

         //All steps completed: 
         die(var_dump($values));

         $flow->reset();
         return $this->redirect($this->generateUrl('home')); // redirect when done
      }

      return array('form' => $form->createView(), 'flow' => $flow);
}

However in the next step the $photo property with the temp filename of the uploaded file get lost, I dump the entity and the value $photo is null (while the others are ok).

in postValidate e preBind events of my Flow class the value is present when I submit the step2 form, but it disappear in the next step.

Any clue?

Thanks!

@craue
Copy link
Owner

craue commented Feb 13, 2012

All step data is serialized into the session. But unfortunately, just serializing file uploads is not possible. You'll have to implement file upload handling yourself and immediately move the uploaded file somewhere. I haven't done that myself using a flow yet.

@craue
Copy link
Owner

craue commented Mar 7, 2012

@madarco: Did you find a way to achieve what you wanted?

@madarco
Copy link
Author

madarco commented Mar 9, 2012

Only with a workaround: I check if there is a file to upload and set the value in the session.
Then, before $flow->bind($values); I do:

 $values->setUploadedPhoto($this->getRequest()->getSession()->get('tmpUploadedFile'));

And when I do $flow->reset(), I also do:

 $this->getRequest()->getSession()->remove('tmpUploadedFile');

@craue
Copy link
Owner

craue commented Mar 11, 2012

So, if there's an uploaded file, you move it and save its path in the session? Do you also handle the case that a file is uploaded but the flow isn't finished (e.g. if the user just leaves the page)?

@madarco
Copy link
Author

madarco commented Mar 13, 2012

No, in that case the file and the session variable will remain there.

I use MongoDB GridFS to store files, so I'll run a job that check for spurious files and remove them...

Not the best solution :)

@craue
Copy link
Owner

craue commented Mar 13, 2012

Alright, but it seems to get the job done. ;)

@craue craue closed this as completed Mar 13, 2012
@tristanbes
Copy link
Contributor

@craue @madarco So, what's the status on this ? I'm facing the same problem with NULL values on the file field.
Can I use your temp solution madarco ?

@madarco
Copy link
Author

madarco commented Jul 1, 2012

yes @tristanbes
It is actually working for me on production

@oopsFrogs
Copy link

Hi, @madarco, I'm a beginner for symfony2, and I also faced the same problem with you. However, I can't figure out how to walkaround with your method. Would you please do me a favor to post detailed code? It would be highly appreciated.

@madarco
Copy link
Author

madarco commented Nov 8, 2012

Sure @oopsFrogs, sorry for the late reply.

My fix is that:

  • on every step of the flow check if the file field is in the request
  • if it is in the request method (ie: was submitted in the html form), save the file in a temp directory, and save in the session the actual path to the file.
  • in the last step, get the value from the session and save the value in your Document or Entity.

This is the code:

What I do is to call a method after the check for $flow->isValid($form) in your action, so that it is executed on every step of the flow:

    if ($flow->isValid($form)) {

        //XXX: fix for unknown bug in FormFlow, we'll handle the photo field manually (not in the Flow class):
        $photo = $this->_fixUploadFile($values->getUploadedPhoto());
        if($photo) {
            $values->setUploadedPhoto($photo);
        }
        //ENDIFX

        if ($flow->nextStep()) {
            ...
        //omissis: check if nextStep()...
        }

        //All steps completed:
        $dm->persist($values);

        //Important!!! clear the variable from the session when you have done:
        $this->getRequest()->getSession()->remove('tmpUploadedFile');
        $dm->flush();

        return $this->redirect(completeUrl);
     }

     //XXX: exec the fix also here, so that in case of validation errors, the user can see the file uploaded in the form:
     $photo = $this->_fixUploadFile($values->getUploadedPhoto());
     if($photo) {
          $values->setUploadedPhoto($photo);
      }
      //ENDIFX

      return array('form' => $form->createView(), 'flow' => $flow, 'values' => $values);

The method _fixUploadFile simply save the file and store in the session the actual file path, to be used in the last step of the flow (when you save it in the db).

This is my method, I upload the file to mongoDb, but the same applies if you save the file on disk too:

    public function _fixUploadFile($file) {

        if(!empty($file) && $file instanceof UploadedFile) {

            $picture = new Picture();
            $picture->setFile($file->getPathname());
            $picture->setExtension($file->guessExtension());
            $picture->setMimetype($file->getMimeType());
            $picture->setType('profile-upload');
            $picture->setSizeType('original');


            $imagine = new Imagine();
            $size = $imagine->open($file->getPathname())->getSize();
            $picture->setWidth($size->getWidth());
            $picture->setHeight($size->getHeight());
            $picture->setOriginalName($file->getClientOriginalName());

            $this->get('doctrine.odm.mongodb.document_manager')->persist($picture);
            $this->get('doctrine.odm.mongodb.document_manager')->flush();       

            $this->getRequest()->getSession()->set('tmpUploadedFile', "" . $picture->getId());
        }
        return $this->getRequest()->getSession()->get('tmpUploadedFile');

    }

@oopsFrogs
Copy link

Thank you, @madarco

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants