This topic is about Symfony – Working Example.
In this chapter, we will learn how to create a complete MVC based BookStore Application in Symfony Framework. Following are the steps.
Step 1: Create a Project
Let’s create a new project named “BookStore” in Symfony using the following command.
symfony new BookStore
Step 2: Create a Controller and Route
Create a BooksController in “src/AppBundle/Controller” directory. It is defined as follows.
BooksController.php
<?php namespace AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Response; class BooksController { /** * @Route("/books/author") */ public function authorAction() { return new Response('Book store application!'); } }
Now, we have created a BooksController, next create a view to render the action.
Step 3: Create a View
Let’s create a new folder named “Books” in “app/Resources/views/” directory. Inside the folder, create a file “author.html.twig” and add the following changes.
author.html.twig
<h3> Simple book store application</h3>
Now, render the view in BooksController class. It is defined as follows.
BooksController.php
<?php namespace AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Response; class BooksController extends Controller { /** * @Route("/books/author") */ public function authorAction() { return $this->render('books/author.html.twig'); } }
As of now, we have created a basic BooksController and the result is rendered. You can check the result in the browser using the URL “http://localhost:8000/books/author”.
Step 4: Database Configuration
Configure the database in “app/config/parameters.yml” file.
Open the file and add the following changes.
parameter.yml
# This file is auto-generated during the composer install parameters: database_driver: pdo_mysql database_host: localhost database_port: 3306 database_name: booksdb database_user: <database_username> database_password: <database_password> mailer_transport: smtp mailer_host: 127.0.0.1 mailer_user: null mailer_password: null secret: 0ad4b6d0676f446900a4cb11d96cf0502029620d doctrine: dbal: driver: pdo_mysql host: '%database_host%' dbname: '%database_name%' user: '%database_user%' password: '%database_password%' charset: utf8mb4
Now, Doctrine can connect to your database “booksdb”.
Step 5: Create a Database
Issue the following command to generate “booksdb” database. This step is used to bind the database in Doctrine.
php bin/console doctrine:database:create
After executing the command, it automatically generates an empty “booksdb” database. You can see the following response on your screen.
It will produce the following result −
Created database `booksdb` for connection named default
Step 6: Mapping Information
Create a Book entity class inside the Entity directory which is located at “src/AppBundle/Entity”.
You can directly pass Book class using annotations. It is defined as follows.
Book.php
Add the following code in the file.
<?php namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name = "Books") */ class Book { /** * @ORM\Column(type = "integer") * @ORM\Id * @ORM\GeneratedValue(strategy = "AUTO") */ private $id; /** * @ORM\Column(type = "string", length = 50) */ private $name; /** * @ORM\Column(type = "string", length = 50) */ private $author; /** * @ORM\Column(type = "decimal", scale = 2) */ private $price; }
Here, the table name is optional.
If the table name is not specified, then it will be determined automatically based on the name of the entity class.
Step 7: Bind an Entity
Doctrine creates simple entity classes for you. It helps you build any entity.
Issue the following command to generate an entity.
php bin/console doctrine:generate:entities AppBundle/Entity/Book
Then you will see the following result and the entity will be updated.
Generating entity "AppBundle\Entity\Book” > backing up Book.php to Book.php~ > generating AppBundle\Entity\Book
Book.php
<?php namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name = "Books") */ class Book { /** * @ORM\Column(type = "integer") * @ORM\Id * @ORM\GeneratedValue(strategy = "AUTO") */ private $id; /** * @ORM\Column(type = "string", length = 50) */ private $name; /** * @ORM\Column(type = "string", length = 50) */ private $author; /** * @ORM\Column(type = "decimal", scale = 2) */ private $price; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set name * * @param string $name * * @return Book */ public function setName($name) { $this->name = $name; return $this; } /** * Get name * * @return string */ public function getName() { return $this->name; } /** * Set author * * @param string $author * * @return Book */ public function setAuthor($author) { $this->author = $author; return $this; } /** * Get author * * @return string */ public function getAuthor() { return $this->author; } /** * Set price * * @param string $price * * @return Book */ public function setPrice($price) { $this->price = $price; return $this; } /** * Get price * * @return string */ public function getPrice() { return $this->price; } }
Step 8: Mapping Validation
After creating entities, you should validate the mappings using the following command.
php bin/console doctrine:schema:validate
It will produce the following result −
[Mapping] OK - The mapping files are correct [Database] FAIL - The database schema is not in sync with the current mapping file.
Since we have not created the Books table, the entity is out of sync. Let us create the Books table using Symfony command in the next step.
Step 9: Creating Schema
Doctrine can automatically create all the database tables needed for Book entity. This can be done using the following command.
php bin/console doctrine:schema:update --force
After executing the command, you will see the following response.
Updating database schema... Database schema updated successfully! "1" query was executed
Now, again validate the schema using the following command.
php bin/console doctrine:schema:validate
It will produce the following result −
[Mapping] OK - The mapping files are correct. [Database] OK - The database schema is in sync with the mapping files.
Step 10: Getter and Setter
As seen in the Bind an Entity section, the following command generates all the getters and setters for the Book class.
$ php bin/console doctrine:generate:entities AppBundle/Entity/Book
Step 11: Fetching Objects from the Database
Create a method in BooksController that will display the books’ details.
BooksController.php
/** * @Route("/books/display", name="app_book_display") */ public function displayAction() { $bk = $this->getDoctrine() ->getRepository('AppBundle:Book') ->findAll(); return $this->render('books/display.html.twig', array('data' => $bk)); }
Step 12: Create a View
Let’s create a view that points to display action. Move to the views directory and create file “display.html.twig”. Add the following changes in the file.
display.html.twig
{% extends 'base.html.twig' %} {% block stylesheets %} <style> .table { border-collapse: collapse; } .table th, td { border-bottom: 1px solid #ddd; width: 250px; text-align: left; align: left; } </style> {% endblock %} {% block body %} <h2>Books database application!</h2> <table class = "table"> <tr> <th>Name</th> <th>Author</th> <th>Price</th> </tr> {% for x in data %} <tr> <td>{{ x.Name }}</td> <td>{{ x.Author }}</td> <td>{{ x.Price }}</td> </tr> {% endfor %} </table> {% endblock %}
You can obtain the result by requesting the URL “http://localhost:8000/books/display” in the browser.
Result
Step 13: Add a Book Form
Let’s create a functionality to add a book into the system. Create a new page, newAction method in the BooksController as follows.
// use section use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; // methods section /** * @Route("/books/new") */ public function newAction(Request $request) { $stud = new StudentForm(); $form = $this->createFormBuilder($stud) ->add('name', TextType::class) ->add('author', TextType::class) ->add('price', TextType::class) ->add('save', SubmitType::class, array('label' => 'Submit')) ->getForm(); return $this->render('books/new.html.twig', array('form' => $form->createView(),)); }
Step 14: Create a View For Book Form
Let’s create a view that points to a new action. Move to the views directory and create a file “new.html.twig”. Add the following changes in the file.
{% extends 'base.html.twig' %} {% block stylesheets %} <style> #simpleform { width:600px; border:2px solid grey; padding:14px; } #simpleform label { font-size:14px; float:left; width:300px; text-align:right; display:block; } #simpleform span { font-size:11px; color:grey; width:100px; text-align:right; display:block; } #simpleform input { border:1px solid grey; font-family:verdana; font-size:14px; color:light blue; height:24px; width:250px; margin: 0 0 10px 10px; } #simpleform textarea { border:1px solid grey; font-family:verdana; font-size:14px; color:light blue; height:120px; width:250px; margin: 0 0 20px 10px; } #simpleform select { margin: 0 0 20px 10px; } #simpleform button { clear:both; margin-left:250px; background: grey; color:#FFFFFF; border:solid 1px #666666; font-size:16px; } </style> {% endblock %} {% block body %} <h3>Book details:</h3> <div id = "simpleform"> {{ form_start(form) }} {{ form_widget(form) }} {{ form_end(form) }} </div> {% endblock %}
It will produce the following screen as output −
Step 15: Collect Book Information and Store It
Let’s change the newAction method and include the code to handle form submission. Also, store the book information into the database.
/** * @Route("/books/new", name="app_book_new") */ public function newAction(Request $request) { $book = new Book(); $form = $this->createFormBuilder($book) ->add('name', TextType::class) ->add('author', TextType::class) ->add('price', TextType::class) ->add('save', SubmitType::class, array('label' => 'Submit')) ->getForm(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $book = $form->getData(); $doct = $this->getDoctrine()->getManager(); // tells Doctrine you want to save the Product $doct->persist($book); //executes the queries (i.e. the INSERT query) $doct->flush(); return $this->redirectToRoute('app_book_display'); } else { return $this->render('books/new.html.twig', array( 'form' => $form->createView(), )); } }
Once the book is stored into the database, redirect to the book display page.
Step 16: Updating the Book
To update the book, create an action, updateAction, and add the following changes.
/** * @Route("/books/update/{id}", name = "app_book_update" ) */ public function updateAction($id, Request $request) { $doct = $this->getDoctrine()->getManager(); $bk = $doct->getRepository('AppBundle:Book')->find($id); if (!$bk) { throw $this->createNotFoundException( 'No book found for id '.$id ); } $form = $this->createFormBuilder($bk) ->add('name', TextType::class) ->add('author', TextType::class) ->add('price', TextType::class) ->add('save', SubmitType::class, array('label' => 'Submit')) ->getForm(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $book = $form->getData(); $doct = $this->getDoctrine()->getManager(); // tells Doctrine you want to save the Product $doct->persist($book); //executes the queries (i.e. the INSERT query) $doct->flush(); return $this->redirectToRoute('app_book_display'); } else { return $this->render('books/new.html.twig', array( 'form' => $form->createView(), )); } }
Here, we are processing two functionalities. If the request only contains id, then we fetch it from the database and show it in the book form. And, if the request contains full book information, then we update the details in the database and redirect to the book display page.
Step 17: Deleting an Object
Deleting an object requires a call to the remove() method of the entity (doctrine) manager.
This can be done using the following code.
/** * @Route("/books/delete/{id}", name="app_book_delete") */ public function deleteAction($id) { $doct = $this->getDoctrine()->getManager(); $bk = $doct->getRepository('AppBundle:Book')->find($id); if (!$bk) { throw $this->createNotFoundException('No book found for id '.$id); } $doct->remove($bk); $doct->flush(); return $this->redirectToRoute('app_book_display'); }
Here, we deleted the book and redirected to book display page.
Step 18: Include Add / Edit / Delete Functionality in Display Page
Now, update the body block in display view and include include add / edit / delete links as follows.
{% block body %} <h2>Books database application!</h2> <div> <a href = "{{ path('app_book_new') }}">Add</a> </div> <table class = "table"> <tr> <th>Name</th> <th>Author</th> <th>Price</th> <th></th> <th></th> </tr> {% for x in data %} <tr> <td>{{ x.Name }}</td> <td>{{ x.Author }}</td> <td>{{ x.Price }}</td> <td><a href = "{{ path('app_book_update', { 'id' : x.Id }) }}">Edit</a></td> <td><a href = "{{ path('app_book_delete', { 'id' : x.Id }) }}">Delete</a></td> </tr> {% endfor %} </table> {% endblock %}
It will produce the following screen as output −
Symfony comprises of a set of PHP components, an application framework, a community and a philosophy. Symfony is extremely flexible and capable of meeting all the requirements of advanced users, professionals, and an ideal choice for all the beginners with PHP.
In this topic we learned about Symfony – Working Example. To know more, Click Here.