My recently released books & Building embedded forms with Symfony2

By Eugenia Pérez | 26 August, 2015

Since two of the books I’ve writing this year are almost ready to go and one of the others is been reviewed by the editors, I’m already working on a new book on Symfony3 Framework. In these two covers, there are still some typos which have been already fixed (I’m sure you’ve already notice that my name shows up as Maria Eugenia? If you know me a little, I guess that you’re laughing right now because you know how much this bothers me… ;-)  )

As it is known, Symfony is one the most widely used frameworks for PHP. As many others it implements the very popular MVC pattern. As all you probably know in this pattern Controllers send data wrapped up in models which then are used by views to present information to the final users. In a web app forms commonly needed to both present and collect data. Forms are linked to models, however sometimes it can be useful to build a form which is intended to pick up information of more than one model. In this context embedded forms play a key role. Let’s assume that we’d like to have a form where users can create tweets and link them to a specific category. Moreover this category has to be one of the many stored in a table of a database. In this scenario a form built for a Tweet class is not enough. We need some kind of hybrid form made up for two classes: Tweet and Category.

Symfony2 includes a special type of field called Entity. This field is a choice field and needs to be related to a class persisted by Doctrine to get the collection of possible values from the table of the database.

The class bellow extends from AbstractType and its goal is to render a form for a Message (Tweet Class). Pay attention to the lines marked in bold related to the Entity field to create a select control to display all the possible categories.

/**
 * Class to centralize the creating of message related forms.
 *
 * @author Eugenia Pérez
 */
class MessageType extends AbstractType {

    /**
     * Creates a new form object to create messages.
     *
     * @param type $action
     * @return type
     */
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                ->add('message', 'text', array('label' => 'Message:'))
                ->add(MessageController::SAVE_BTN, 'submit', array(
                    'label' => 'Post',
                    'attr' => array('class' => 'btn btn-sm btn-info')))
                ->add(MessageController::HIGHLIGHT_BTN, 'submit', array(
                    'label' => 'Post & Highlight',
                    'attr' => array('class' => 'btn btn-sm btn-success')))
                ->add('tag', 'entity', array(
                    'class' => 'AppBundle:Tag'));

        if ($options != null && $options['action'] != null) {
            $builder->setAction($options['action']);
        }
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(
array('data_class' => 'AppBundle\Entity\Text'));
    }

    public function getName() {
        return 'message';
    }

}

Once this is set up, taking care of the data send by the client needs no especial handling. It’s just a regular action that uses the handle request method to read the data and then Doctrine takes control of it to persist the Message Entity including the link to the Category selected by the user.

/**
     * Receives the data sent by the user to create a new message.
     *
     * @Route("/message", name="new_message")
     * @Method({"POST"})
     */
    public function createAction(Request $request) {
        $text = new Text();

        $postForm = $this->createForm(new MessageType(), $text);
        $postForm->handleRequest($request);

        if ($postForm->isValid()) {
            $text = $postForm->getData();
            $text->setCreationDate(new DateTime());

            $em = $this->getDoctrine()->getManager();
            $em->persist($text);
            $em->flush();
            return $this->render('alert/success.html.twig', array('info' => 'Message published successfully'));
        } else {
            return $this->render('message/index.html.twig', array(
                        'postForm' => $postForm->createView()));
        }
    }

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather