2

We have an old website where I have implemented a form that is sent by AngularJS to a PHP script and after processing an email message get sent. If the form is not valid the PHP script returns a JSON with the validation errors. Since we already use Symfony for some other applications (REST APIs), I thought it would be nice to reimplement my plain PHP script in Symfony.

For the sake of simplicity I put only a small but relevant fragment of my code. This is what I have:

HTML (ng-app is bound on body tag, not shown here):

<form name="infoscreenForm" class="form-horizontal" enctype="multipart/form-data" ng-controller="FormController">
    <div class="form-group">
        <div class="col-lg-1 control-label">*</div>
        <div class="col-lg-11 input-group">
            <input type="text" class="form-control" id="contact_person"
                   name="contact_person" ng-model="formData.contactPerson"
                   placeholder="Kontaktperson">
        </div>
        <span class="text-warning" ng-show="errors.contactPerson">
            {{ errors.contactPerson }}
        </span>
    </div>
    <div class="form-group">
        <div class="col-lg-1 control-label">*</div>
        <div class="col-lg-11 input-group">
            <span class="input-group-addon">@</span>
            <input type="email" class="form-control" id="email" name="email"
                   ng-model="formData.email" placeholder="E-Mail">
        </div>
        <span class="text-warning" ng-show="errors.email">
            {{ errors.email }}
        </span>
    </div>
    <div class="form-group">
        <div class="col-lg-1 control-label">&nbsp;</div>
        <div class="col-lg-11 input-group">
            <input type="file" class="form-control" id="file" name="file"
                   file-model="formData.file"
                   accept="application/pdf,image/jpeg,image/png">
        </div>
        <span class="text-warning" ng-show="errors.file">
            {{ errors.file }}
        </span>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-default" id="submit"
                name="submit" ng-click="submitForm()">
            Formular absenden
        </button>
    </div>
</form>

JS:

var app = angular.module('InfoscreenApp', []);

app.directive('fileModel', ['$parse', function ($parse) {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      var model = $parse(attrs.fileModel);
      var modelSetter = model.assign;

      element.bind('change', function () {
        scope.$apply(function () {
          modelSetter(scope, element[0].files[0]);
        });
      });
    }
  };
}]);

app.factory('multipartForm', ['$http', function ($http) {
    return {
      post : function (uploadUrl, data) {
        var fd = new FormData();
        for (var key in data) {
          fd.append(key, data[key]);
        }
        return $http.post(uploadUrl, fd, {
            transformRequest: angular.identity,
            headers : { 'Content-Type': undefined }

        });
      }
    };
}]);

app.controller('FormController', ['$scope', 'multipartForm', function ($scope, multipartForm) {
    $scope.formData = {};

    $scope.submitForm = function () {
      var uploadUrl = 'http://localhost:8000/infoscreen';
      multipartForm.post(uploadUrl, $scope.formData)
      .then(function (data) {
        console.log(data);

        if (data.success) {
          $scope.message = data.data.message;
          console.log(data.data.message);
        } else {
          $scope.errors = data.data.errors;
        }
      });
    };
}]);

With the plain PHP script everything works fine. Here is what I tried to do in Symfony:

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;

class DefaultController extends Controller
{
    /**
     * @Route("/infoscreen", name="infoscreen")
     */
    public function infoscreenAction(Request $request)
    {
        $defaultData = array('message' => 'infoscreenForm');
        $form = $this->createFormBuilder($defaultData)
            ->add('contactPerson', TextType::class, array(
                'constraints' => array(
                    new NotBlank(),
                )
            ))
            ->add('email', EmailType::class, array(
                'constraints' => array(
                    new NotBlank(),
                    new Email(),
                )
            ))
            ->add('file', FileType::class)
            ->add('submit', SubmitType::class)
            ->getForm();
        ;

        $form->submit($request->request->get($form->getName()));
        $data = $form->getData();

        if ($form->isValid()) {
            echo 'Alles ok';
            // send an email
        }

        $errors = array();
        $validation = $this->get('validator')->validate($form);
        foreach ($validation as $error) {
            $errors[$error->getPropertyPath()] = $error->getMessage();
        }

        $response = new Response();
        $response->setContent(json_encode(array(
            'form_data' => $data,
            'errors' => $errors,
        )));
        $response->headers->set('Content-Type', 'application/json');

        return $response;
    }
}

CSRF is disabled in config.yml. The form is not bound to an entity class. After submitting the form I get the following object in the console:

{
    data: Object,
    status: 200,
    config: Object,
    statusText: "OK"
}

The important part is in data: Object:

{
    form_data: {
        contactPerson: null,
        email: null,
        message: "infoscreenForm",
        file: null
    },
    errors : {
        children[contactPerson].data = "This value should not be blank",
        children[email].data = "This value should not be blank"
    }
}

This happens when I submit the form with some values entered in the fields. It seems that the submitted data is not bound to the form in the controller. I'm probably missing something, but I stuck here and have no idea how to proceed. I tried with $form->bind($request), $form->handleRequest($request) and few other things, but it didn't work. Even if I bind the fields individually, I still don't get their values in the form.

Can somebody please help me.

Thanks in advance.

1 Answer 1

2

Try

$this->get('form.factory')->createNamedBuilder(null, 'form', $defaultData)

instead of

$this->createFormBuilder($defaultData)
Sign up to request clarification or add additional context in comments.

1 Comment

Yes, this does the trick. I had also to bind the form with $form->bind($request) and now I get the values. Thank you very much! большо́е спаси́бо!

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.