1
votes

I am using the FOSUserBundle and I extended the registration form to input the name of a company when registering a new user. Company is a separate Entity. I created all required methods for the relation handling.

/**
 * User entity
 */
class User {
    // ...
    addCompany() { /* ... */ }
    removeCompany() { /* ... */ }
    getCompanies() { /* ... */ }
}

I followed the Symfony guide to embed a Single Object to a form:

class RegistrationFormType extends \FOS\UserBundle\Form\Type\RegistrationFormType
{
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('...')
            ->add('company', new CompanyType());
    }
    // ...
}

The registration form is rendered properly; it shows a field for the Company name. But when I submit, I get

Neither the property "company" nor one of the methods "setCompany()", "_set()" or "_call()" exist and have public access in class "Acme\MyBundle\Entity\User".

I obviously neither don't have a company property nor a setCompany() method, because it's a manyToMany relationship, thus I have a companies property and a addCompany() method instead.

Questions

  • Why doesn't Symfony also look for a addCompany() method?
  • Should I implement a setCompany() method (e.g. by simply renaming accordingly, or as a wrapper method which calls addCompany())?
  • Or is this due to the singular/plural problem which comes up when singular and plural method names can't be interpreted correctly by Symfony?
1

1 Answers

3
votes

What you're after is the by_reference option.

There are 2 cases:

  1. by_reference => true and therefore the setters are called (by default).

  2. by_reference => false and therefore the adders are called.

What you're trying to do is exactly this : 

How to Embed a Collection of Forms.


Edit 1: The OP wishes to user adders instead of setters

Try this:

$builder->add('company', 'collection', array(
    'type'   => new CompanyType(),
    'options'  => array(
        'by_reference'  => false,
    ),
));

Edit 2: The OP wishes to create only one company per user

class UserController extends Controller
{
    public function whateverAction(Request $request)
    {
        $user = new User();

        $company = new Company();
        $user->getCompany()->add($company);

        $form = $this->createForm(new UserType(), $user);

        $form->handleRequest($request);

        if ($form->isValid()) {
            // form processing
        }

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

Edit 3: The OP only wants to override the FOSUserBundle form type

You still have the option to create a setter in your entity to solve your issue.

/**
 * Set Category
 *
 * @param ArrayCollection $category
 */
public function setCategory($category) {

    $this->category->clear();

    foreach ($category as $cat) {
        $this->addCategory($cat);
    }

    return $this;
}

Note: It would be a better practice to use $categories instead of $category if you have a OneToMany so that you know that it's a collection. You would have in your entity:

  • $companies
  • getCompanies()
  • setCompanies($companies)
  • addCompany($company)
  • removeCompany($company)