0

I have a symfony 2 form that describes a package:

class PackageType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->setMethod('POST')
            ->add('deliveryNote')
            ->add('receiver', new ReceiverType());

        // field stockitem exists, added dynamically NOT good

    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'IREnterprise\AppBundle\Entity\Package',
            'csrf_protection'   => false,
            'allow_extra_fields' => true
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'IREnterprise_AppBundle_package';
    }
}

Each package has 1 receiver, and a dynamic amount of package lines that are associated with the package, each package line contains one stockitem.

The idea is that the user is able to add existing StockItems, as package lines.

I have achieved that, and it looks like this: enter image description here every time the user clicks addPackageLine a package line is added to the form, and he can pick a stockItem and the amount of that stockItem.

Anyway, i had to do something hackish to get around the formBuilder.

So the controller ends up looking like this:

public function newPackageAction(Request $request)
{
    $package = new Package();
    $form = $this->createForm(new PackageType(), $package);
    $form->handleRequest($request);

    // Test if stock item belongs to user, and add to package
    $formStockItems = $request->request->get('IREnterprise_AppBundle_package[stockItems]', null, true);

    // This is bad ... very bad, should be a doctrine validation
    if (empty($formStockItems)) {
        $form->add('packageLines')->addError(new FormError('Package Lines cannot be null'));
    }


    if ($form->isValid()) {

        $em = $this->getDoctrine()->getManager();

        $package->setUser($this->getUser());

        foreach ($formStockItems as $formStockItem) {
            $stockItem = $em->getRepository('IREnterpriseAppBundle:StockItem')
                ->findByUserAndId($this->getUser(), $formStockItem['item']);

            if (!empty($stockItem)) {

                // Create a package line for the stock item, and add it the line to the package
                $packageLine = new PackageLine();
                $packageLine->setStockItem($stockItem);
                $packageLine->setAmount($formStockItem['quantity']);
                $packageLine->setPackage($package);

                $package->addPackageLine($packageLine);
            }
        }

        $em->persist($package);
        $em->flush();

        $response = View::create($package);
        return $response;
    }

    return View::create($form, Response::HTTP_BAD_REQUEST);

}

I would like to do this in a less hackish way, so that form->isValid() also validates all the packageLiens sent along, because my form errors become messed up with this approach, any suggestions?

1
  • I've only skimmed your question but have a look at the documentation for Form Events and Form Collections, I think some of it might be applicable. Commented Jul 11, 2015 at 17:22

1 Answer 1

1

Use the "collection" form type in symphony. See the How to Embed a Collection of Forms document for complete details, but the basics are that the collection type takes an option "type", which specifies the form type for each element of the collection.

You can also specify "allow_add" and "allow_delete" options to allow it to be dynamically sized.

using "allow_add" also enables a way to create a "prototype" form field that can be used by your javascript to render the form for new items in this collection

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

Comments

Your Answer

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