Code Faster Symfony2s Interactive Generators

When building a Symfony2 application, there are some tasks that you always do. In the lifetime of every project, you will create around 2 bundles, 5 and 10 entities, and for almost all entities, you will implement a CRUD (Create, Read, Update, Delete) interface with controllers and templates to deal with them. Symonfy2's interactive generators save you a lot of time. Currently, there are 3 of them:

  • generate:bundle generates a new bundle

  • generate:doctrine:entity generates a new entity

  • generate:doctrine:crud generates a CRUD based on an entity

Before starting, get excited by watching the screencast made by the Symfony2 team.

New Bundle

To create a new bundle, run the command:

app/console generate:bundle

It will launch an assistant that will ask you these questions: Bundle namespace, Bundle name, Target directory, Configuration format (yml, xml, php, or annotation). And you have a running bundle, you don't have to bother about anything else! The script took care of adding the bundle to the autoloader, subscribing it in the kernel and adding routing rules. It has already a default controller with a basic function that you can start to play with:

class DefaultController extends Controller
{
    /**
     * @Route("/hello/{name}")
     * @Template()
     */
    public function indexAction($name)
    {
        return array('name' => $name);
    }
}

And a template for this controller:

Hello !

New Entity

Instead of creating all your entities by creating and editing the PHP files in MyBundle/Entity, just run the command:

app/console generate:doctrine:entity

Follow the wizard and declare the name of your entity and the fields you want. The script will generate all the code for you. Here is an example of the code generated with only one field name:

/**
 * Acme\Bundle\BlogBundle\Entity\Post
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Acme\Bundle\BlogBundle\Entity\PostRepository")
 */
class Post {
    /**
     * @var integer $id
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string $name
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * Get id
     * @return integer $id
     */
    public function getId() {
        return $this->id;
    }

    /**
     * Set name
     * @param string $name
     */
    public function setName($name) {
        $this->name = $name;
    }

    /**
     * Get name
     * @return string $name
     */
    public function getName() {
        return $this->name;
    }
}

See how much time you just saved ? It can even generate an empty repository for this entity if you say yes during when you are asked the question:

namespace Acme\Bundle\BlogBundle\Entity;
use Doctrine\ORM\EntityRepository;

/**
 * PostRepository
 * This class was generated by the Doctrine ORM.
 * Add your own custom repository methods below.
 */
class PostRepository extends EntityRepository {
}

Entity CRUD generator

But the real time saver is the CRUD generator. You run the command:

app/console generate:doctrine:crud

Answer the question (what bundle, write actions or not, route prefix, etc.) and it will generate a new controller with all the method to deal with this entity and the corresponding templates. Here is for example the update action for my entity that the script just generated:

/**
 * Edits an existing Post entity.
 *
 * @Route("/{id}/update", name="post_update")
 * @Method("post")
 * @Template("AcmeBundleBlogBundle:Post:edit.html.twig")
 */
public function updateAction($id)
{
    $em = $this->getDoctrine()->getEntityManager();

    $entity = $em->getRepository('AcmeBundleBlogBundle:Post')->find($id);

    if (!$entity) {
        throw $this->createNotFoundException('Unable to find Post entity.');
    }

    $editForm   = $this->createForm(new PostType(), $entity);
    $deleteForm = $this->createDeleteForm($id);

    $request = $this->getRequest();

    if ('POST' === $request->getMethod()) {
        $editForm->bindRequest($request);

        if ($editForm->isValid()) {
            $em = $this->getDoctrine()->getEntityManager();
            $em->persist($entity);
            $em->flush();

            return $this->redirect($this->generateUrl('post_edit', array('id' => $id)));
        }
    }

    return array(
        'entity'      => $entity,
        'edit_form'   => $editForm->createView(),
        'delete_form' => $deleteForm->createView(),
    );
}

and the template:

<h1>Post edit</h1>

<form action="{{ path('post_update', { 'id': entity.id }) }}" method="post" {{ form_enctype(edit_form) }}>
    {{ form_widget(edit_form) }}
    <p>
        <button type="submit">Edit</button>
    </p>
</form>

<ul class="record_actions">
    <li>
        <a href="{{ path('post') }}">
            Back to the list
        </a>
    </li>
    <li>
        <form action="{{ path('post_delete', { 'id': entity.id }) }}" method="post">
            {{ form_widget(delete_form) }}
            <button type="submit">Delete</button>
        </form>
    </li>
</ul>

Now you just saved one day of work, you can take your week-end on thursday night! Further reading:

And more commands to come!

Quentin Pleplé
July 2011