We hope you find this tutorial helpful. In addition to guides like this one, we provide simple cloud infrastructure for developers. Learn more →

How To Use Symfony2 To Perform CRUD Operations on a VPS (Part 2)

PostedSeptember 6, 2013 49.8k views PHP Frameworks

About Symfony

Symfony is an open source PHP web development framework - a set of tools and methodology to help you build great applications. Some of the traits of this framework are its speed, flexibility, scalability, and stability. You can use it for a full blown web application but also for smaller functionalities needed for your project.

In the previous tutorial, we began creating a small application to illustrate how to perform CRUD (create, read, update, delete) operations using the Symfony2 framework. For this, we installed the Symfony2 Standard Distribution and started working with our news articles from the database - that if you followed all the steps, you should see at www.example.com/Symfony/web/app_dev.php/news/.

What we’ll do in this tutorial is see how to perform the rest of the CRUD operations - create, update and delete - using the same data module we started working with in the last one. Therefore it’s assumed that you have gone through the previous tutorial before starting this one.

Creating data

In order to create data, let's first create another route to the form page for adding our news article. So let’s edit the routing.yml file from our NewsBundle:

nano /var/www/Symfony/src/Foo/NewsBundle/Resources/config/routing.yml

And add a new route:

foo_news_add:
    pattern:  /news/add/
    defaults: { _controller: FooNewsBundle:Default:add }

What you may notice now is that you’ll have a conflict with the pattern from the route we created previously (foo_news_show) as it will look at the word add and think it’s the ID of the news that needs to be found. So let’s edit the foo_news_show route and create a requirement that the {id} variable is a integer. So transform it like so:

foo_news_show:
    pattern:  /news/{id}
    defaults: { _controller: FooNewsBundle:Default:show }
    requirements:
        id:  \d+

Okay, save the file and let’s now create our addAction() method in the DefaultController to act as the callback for this route. So let's edit the DefaultController.php file:

nano /var/www/Symfony/src/Foo/NewsBundle/Controller/DefaultController.php

The first thing to do is we need to make sure the class loads the News entity class, the Symfony Request component for the Form processing, and the Response component. So at the top of the file below the namespace declaration, add the following line:

use Foo\NewsBundle\Entity\News;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

Now, below the showAction() method, let’s add the new addAction() method:

public function addAction(Request $request) {

     $news = new News();
     $news->setCreatedDate(new \DateTime());
    
     $form = $this->createFormBuilder($news)
        ->add('title', 'text')
        ->add('body', 'text')
        ->add('save', 'submit')
        ->getForm();

     $form->handleRequest($request);    
     if ($form->isValid()) {
       $em = $this->getDoctrine()->getManager();
       $em->persist($news);
       $em->flush();
       return new Response('News added successfuly');
     }
    
     $build['form'] = $form->createView();
     return $this->render('FooNewsBundle:Default:news_add.html.twig', $build);
 }

What happens here then? First we instantiate a News object and set its created date to the current time. Then we use the Symfony form builder to create a form that has two fields (that match the properties in our News entity) and a submit button. At the end of the function, we then create the form and pass it to the news_add.html.twig template file in the form variable for it to be displayed. Let’s quickly create that file and then we’ll come back to explain the form processing part. So create the new template in the place where you created the rest:

nano /var/www/Symfony/src/Foo/NewsBundle/Resources/views/Default/news_add.html.twig

And add the following simple line in it:

{{ form(form) }}

Save and test the page by pointing your browser to the new route and you should see the form:

www.example.com/Symfony/web/app_dev.php/news/add

Now what happens if you submit it? If you look in the addAction() method we just created, you’ll see this block we didn’t talk yet about:

  $form->handleRequest($request);    
     if ($form->isValid()) {
       $em = $this->getDoctrine()->getManager();
       $em->persist($news);
       $em->flush();
       return new Response('News added successfully');
     }

This basically checks if a form request has been passed (remember the Request object being passed as an argument?) and if it is valid, then automatically updates the $news object we just created and uses the doctrine manager to persist it to the database. Then it creates a new Response object with the success message to be printed on the screen. If no form requests comes in, it will skip these steps and display the form in the normal way. Simple.

Updating data

Now that we know how to read the news pages and add new ones, updating them will be really easy - it is basically combining the two actions. Like always, let’s add a new route to our routing.yml file:

nano /var/www/Symfony/src/Foo/NewsBundle/Resources/config/routing.yml

And our route for editing:

foo_news_edit:
    pattern:  /news/{id}/edit
    defaults: { _controller: FooNewsBundle:Default:edit }
    requirements:
        id:  \d+

As you can see, we maintain the requirement for the {id} to be an integer and we point to a new method in the same Controller called editAction() - that we will now have to create. So let’s edit the class file again:

nano /var/www/Symfony/src/Foo/NewsBundle/Controller/DefaultController.php

And add the new method:

public function editAction($id, Request $request) {

    $em = $this->getDoctrine()->getManager();
    $news = $em->getRepository('FooNewsBundle:News')->find($id);
    if (!$news) {
      throw $this->createNotFoundException(
              'No news found for id ' . $id
      );
    }
    
    $form = $this->createFormBuilder($news)
        ->add('title', 'text')
        ->add('body', 'text')
        ->add('save', 'submit')
        ->getForm();

    $form->handleRequest($request);
 
    if ($form->isValid()) {
        $em->flush();
        return new Response('News updated successfully');
    }
    
    $build['form'] = $form->createView();

    return $this->render('FooNewsBundle:Default:news_add.html.twig', $build);
 }

What happens here is quite simple again. The difference between this method and addAction() is that instead of us instantiating a new News entity, we retrieve an existing one from the database. The resulting $news object will then again be the basis for the form building. And as you notice, we can use the same template file for rendering the form in this simple example. Another small difference is that we get the entity manager early on and we won’t have to use its persist() method in the form processing because the $news object is already being managed by it. So using flush() is enough to save it into the database.

You can go ahead and try to edit the news page with the ID 1 at www.example.com/Symfony/web/app_dev.php/news/1/edit and you’ll see the results.

Deleting data

The last thing we’ll look at in this tutorial is how to remove our news pages. So like usual, let’s set up a route that will take us to a delete confirmation page. So edit the routing.yml file again:

nano /var/www/Symfony/src/Foo/NewsBundle/Resources/config/routing.yml

And paste in the following route:

foo_news_delete:
    pattern:  /news/{id}/delete/
    defaults: { _controller: FooNewsBundle:Default:delete }
    requirements:
        id:  \d+

Next, let’s create the method deleteAction() in our DefaultController. Edit the class file:

nano /var/www/Symfony/src/Foo/NewsBundle/Controller/DefaultController.php

And add the new method:

public function deleteAction($id, Request $request) {

    $em = $this->getDoctrine()->getManager();
    $news = $em->getRepository('FooNewsBundle:News')->find($id);
    if (!$news) {
      throw $this->createNotFoundException(
              'No news found for id ' . $id
      );
    }

    $form = $this->createFormBuilder($news)
            ->add('delete', 'submit')
            ->getForm();

    $form->handleRequest($request);

    if ($form->isValid()) {
      $em->remove($news);
      $em->flush();
      return new Response('News deleted successfully');
    }
    
    $build['form'] = $form->createView();
    return $this->render('FooNewsBundle:Default:news_add.html.twig', $build);
}

This method does most of what editAction() does except that instead of building an edit form it just outputs a submit button for deleting the $news object that was retrieved. Then when the form is submitted, we use remove() method of the entity manager to delete the news page from the article. And you’ll notice that again we are using the same template file: news_add.html.twig.

If you now navigate to www.example.com/Symfony/web/app_dev.php/news/1/delete, all you will see though is a delete button. So let’s add a small modification to our template file so that in case a delete button is present, to include also some text. So edit the template file:

nano /var/www/Symfony/src/Foo/NewsBundle/Resources/views/Default/news_add.html.twig

And above what’s already in there, paste the following:

{% if form.delete is defined %}
      Are you sure you want to delete the news page: {{ form.vars.value.title }} ?
    {% endif %}

This will print out a confirmation text that includes the title of the news page in the question (taken from the form variable passed to the template). Now if you refresh the page, you’ll see it there and you can click delete in order to remove the news with the ID 1. You should then get a confirmation message delivered by the Response object we created.

Clean up

We’ve now implemented the core CRUD operations so it’s time to finalize our small application by rounding it up a bit. This means adding some links on the news listing page that would quickly allow you to perform operations. We’ve seen how to create links in the template in the last tutorial so now it shouldn’t be a problem. Edit the news_show_all.html.twig template file and let’s add some admin links:

nano /var/www/Symfony/src/Foo/NewsBundle/Resources/views/Default/news_show_all.html.twig

Below the following line:

<h3><a href="{{ path('foo_news_show', {'id':  new.Id  }) }}">{{ new.Title }}</a></h3>

Paste this:

<a href="{{ path('foo_news_edit', {'id':  new.Id  }) }}">Edit</a> | <a href="{{ path('foo_news_delete', {'id':  new.Id  }) }}">Delete</a><hr />

And at the top of the page paste this:

<a href="{{ path('foo_news_add') }}">Add news</a>

Now go to www.example.com/Symfony/web/app_dev.php/news/ and see it in action. There, you will have links to edit and delete each news page as well as a top link to create new pieces of news.

Conclusion

In this and the previous tutorials, we’ve seen how to build a small Symfony2 application that performs CRUD on our data model, the news pages. Your DefaultController.php class file should now look something like this:

<?php

namespace Foo\NewsBundle\Controller;

use Foo\NewsBundle\Entity\News;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller {

  public function indexAction() {
    $news = $this->getDoctrine()
            ->getRepository('FooNewsBundle:News')
            ->findAll();
      if (!$news) {
        throw $this->createNotFoundException('No news found');
      }
    
      $build['news'] = $news;
      return $this->render('FooNewsBundle:Default:news_show_all.html.twig', $build);
  }

  public function showAction($id) {
      $news = $this->getDoctrine()
            ->getRepository('FooNewsBundle:News')
            ->find($id);
      if (!$news) {
        throw $this->createNotFoundException('No news found by id ' . $id);
      }
    
      $build['news_item'] = $news;
      return $this->render('FooNewsBundle:Default:news_show.html.twig', $build);
   }

   public function addAction(Request $request) {

     $news = new News();
     $news->setCreatedDate(new \DateTime());
    
     $form = $this->createFormBuilder($news)
        ->add('title', 'text')
        ->add('body', 'text')
        ->add('save', 'submit')
        ->getForm();

     $form->handleRequest($request);    
     if ($form->isValid()) {
       $em = $this->getDoctrine()->getManager();
       $em->persist($news);
       $em->flush();
       return new Response('News added successfuly');
     }
    
     $build['form'] = $form->createView();
     return $this->render('FooNewsBundle:Default:news_add.html.twig', $build);
  }

  public function editAction($id, Request $request) {

    $em = $this->getDoctrine()->getManager();
    $news = $em->getRepository('FooNewsBundle:News')->find($id);
    if (!$news) {
      throw $this->createNotFoundException(
              'No news found for id ' . $id
      );
    }
    
    $form = $this->createFormBuilder($news)
        ->add('title', 'text')
        ->add('body', 'text')
        ->add('save', 'submit')
        ->getForm();

    $form->handleRequest($request);
 
    if ($form->isValid()) {
        $em->flush();
        return new Response('News updated successfully');
    }
    
    $build['form'] = $form->createView();

    return $this->render('FooNewsBundle:Default:news_add.html.twig', $build);
  }

  public function deleteAction($id, Request $request) {

    $em = $this->getDoctrine()->getManager();
    $news = $em->getRepository('FooNewsBundle:News')->find($id);
    if (!$news) {
      throw $this->createNotFoundException(
              'No news found for id ' . $id
      );
    }

    $form = $this->createFormBuilder($news)
            ->add('delete', 'submit')
            ->getForm();

    $form->handleRequest($request);

    if ($form->isValid()) {
      $em->remove($news);
      $em->flush();
    }
    
    $build['form'] = $form->createView();
    return $this->render('FooNewsBundle:Default:news_add.html.twig', $build);
  }

}

Although this has been very simple, Symfony2 is capable of scaling up to much more complex data, structured in multiple tables and perform wonders when it comes to managing it. Lastly, using the Twig templating system with Symfony allows you to create very powerful and easy to manage websites. Good luck!

Article Submitted by: Danny

7 Comments

Creative Commons License