0

I am trying to upload file with Symfony3 but with no luck. I have a Profile entity which is linked to User entity with 1-1 relationship. The profile contains a picture column. I have created a ProfileType and Profile Model. Upon submitting the form, the model contains only the File name and nothing else. The $_FILES array is also empty. This is the code.

        $builder
        ->add("name", TextType::class, array(
        "required" => true,
    ))
        ->add("email", EmailType::class, array(
            "required" => true,
        ))
        ->add("city", TextType::class, array(
            "required" => false,
        ))
        ->add("country", ChoiceType::class, array(
            "required" => false,
        ))
        ->add("picture", FileType::class, array(
            "required" => false,
        ));



class ProfileModel
{
  private $name;
  private $email;
  private $city;
  private $country;
  private $picture;

In Controller I am creating the form like this.

$profileForm = $this->createForm(ProfileType::class, $profileModel);

When I get the picture, It contains just the name.

$file = $profileForm->get("picture")->getData();
5
  • symfony.com/doc/current/controller/upload_file.html Commented Aug 14, 2016 at 13:52
  • I have already read about SonataBundle but I don't want to be dependent on another new bundle just for files upload. I want to do it using core Symfony3. Commented Aug 14, 2016 at 14:05
  • Where you see sonata in this link? Just read how to upload file, it's not enough to make form field of type file and expect miracles. Commented Aug 14, 2016 at 14:19
  • @malcolm the sonata Bundle comment was not for you. It was for those who might have suggested it. Secondly I don't expect magic to happen. At least the $_FILES array should contain the file info after clicking the submit button, right? Commented Aug 14, 2016 at 14:53
  • Yes, if you have configured PHP for sending files. You can always check logs, it should be first place to check before posting to SO. Commented Aug 14, 2016 at 15:06

3 Answers 3

3

Hewwo rashidkhan~

Symfony doc is quite complete on the upload process, did you read it?
http://symfony.com/doc/current/controller/upload_file.html

After a few modifications, I choose to use it as service. Here is the process:

1) Add a few parameters to app/config/config.yml:

under parameters:

parameters:
    locale: en
    profile_directory: '%kernel.root_dir%/../web/upload/profile'
    another_directory: '%kernel.root_dir%/../web/upload/another'

under twig

twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
globals:
    profile_directory: '/upload/profile/'
    another_directory: '/upload/another/'

The two profile_directoryadded just now will be used as variables in both your upload service and twig to point the targer directory. I added another_directory to explain something more a bit after.

2) Create the service:

Create a new file under src/YourBundle/Services/FileUploader.php
From here, my code is a bit different than what you can find on the Symfony site.

FileUploader.php content:

<?php

namespace YourBundle\Services;

use YourBundle\Entity\ProfileModel;
use YourBundle\Entity\Another;

class FileUploader {
    private $profileDir;
    private $anotherDir;

    public function __construct($profileDir) {
        $this->profileDir=$profileDir;
        $this->anotherDir=$anotherDir;
    }

    public function upload($class) {
        if($class instanceof ProfileModel) {
            $file=$class->getPicture();
            $fileName='picture-'.uniqid().'.'.$file->guessExtension();
            $file->move($this->profileDir, $fileName);
            $class->setPicture($fileName);
        }

        if($class instanceof Another) {
            $file=$class->getPicture();
            $fileName='picture-'.uniqid().'.'.$file->guessExtension();
            $file->move($this->anotherDir, $fileName);
            $class->setPicture($fileName);
        }

        return $class;
    }
}

3) Register the service to app/config/services.yml:

under services:

services:
    app.file_uploader:
    class: YourBundle\Services\FileUploader
    arguments:
        - '%profile_directory%'
        - '%another_directory%'

Each argument must be in the same order as your privatein the FileUploader.php file. Those arguments are the ones we setted in app/config/config.yml under parameters.

4) Edit your controller:

The controller part is quite simple.

Add use Symfony\Component\HttpFoundation\File\File; in the import section

Under newAction

public function newAction(Request $request)
{
    $profileModel = new ProfileModel();
    $form = $this->createForm('YourBundle\Form\ProfileModelType', $profileModel);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        // We upload the file with this line
        $profileModel=$this->get('app.file_uploader')->upload($profileModel);
        $em = $this->getDoctrine()->getManager();
        $em->persist($profileModel);
        $em->flush();

        return $this->redirectToRoute('profile_model_show', array('id' => $profileModel->getId()));
    }

    return $this->render('YourBundle:Default:new.html.twig', array(
        'profileModel' => $profileModel,
        'form' => $form->createView(),
    ));
}

Under editAction

public function editAction(Request $request, ProfileModel $profileModel)
{
    // Add this live above everything else in the code.
    $profileModel->setPicture(new File($this->getParameter('profile_directory').'/'.$profileModel->getPicture()));
    [...]
}

I haven't gone more far, so I can only explain what to modify after... In your editAction, you will also have to check that $_FILES isn't empty. If it's not, then you do the upload process. If it's, then make sure to not edit the picture column in the SQL query (you will have to do a custom query)

5) Your twig views:

Under show.html.twig

Change

<tr>
    <th>Picture</th>
    <td>{{ profileModel.picture) }}</td>
</tr>

to

<tr>
    <th>Picture</th>
    <td><img src="{{ asset(profile_directory~profileModel.picture) }}"></td>
</tr>

Same goes for the index.html.twig. And you can add (not replace) it to the edit.html.twig to get a preview of the actual picture.

6) Explanations:

In app/config/config.yml we added a few directory to use as parameters in your files.
It will later make it easier to change those directories if needed. (Won't have to edit tons of files... YAY!)
Twig directories always start from the /web folder.

Those directory are used when we register our service as arguments. They will set our variable in the service file FileUploader.php.

Unlike the Symfony site exemple, we pass the whole object to the upload service. We then, check from which class this object was created and do our upload process based in it.

Your upload process in the controller is then shortened to a single line.

In twig, we will also use the directory variable set in app/config/config.yml undet the twigproperty. Like said above, if our upload directory change, we will then just have to edit the app/config/config.yml file.


I hope this will help you solve your upload issues.

Cordially,
Preciel.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you @preciel for your detailed answer. I am upvoting you for your effort and time. I had created the form using the html <form> tag and didn't use the form_start of twig. The body of form was constructed using macros. The problem was that I didn't that I didn't add the enctype="multipart/form-data" to the form. When I added it, the file upload started working. Thank you to everyone.
0

You should try

$form = $this->createForm(ProfileType::class, $profileModel); $form->handleRequest($request); $file = $profileModel->getBrochure();

More: http://symfony.com/doc/current/controller/upload_file.html

3 Comments

I have validated the form using handleRequest but I did not show the full code because there was not need for. Instead of getBrochure, I have getPicture().
I meant replace $file = $profileForm->get("picture")->getData(); to $file = $profileModel->getPicture();
If you read the description, I have already said the Model contains only the file name. I have tried to get the file from Model, from Submitted Form and from $_FILES array.
0

Guys if you want to upload any kind of file in Symfony then I have very simple solution, which I have mentioned in the below. Why I am giving simple solutions because whenever new version come, you have to do some settings in services.yaml or you have to create extra files apart from your main controller.

So solutions is: Just use move($storing_place, $actual_filename) function in your main controller.

Put below codes in your controller file.

$folder_path = 'public/uploads/brochures/';
$file = $request->files->get('myfile');
$fileName = $request->files->get('myfile')->getClientOriginalName();
$file->move($folder_path, $fileName);        
return new Response($file);

Hope given solution will help in your project.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.