how to create a complete MVC based BookStore Application in Symfony Framework.
PHP built-in development web server (Multi-platform)
Operating System: Cross-platform
UNIX/Linux based OS
Apache2 server with PHP7 installed
MySQL database
Browser Support: IE (Internet Explorer 8+), Firefox, Google Chrome, Safari, Opera
PHP Compatibility: PHP 5.4 or later. To get the maximum benefit, use the latest version.
In this tutorial, we will figure out how to make a total MVC based BookStore Application in Symfony Framework. Here is the 18 steps in the following which we will used in creation.
first of all we will create a new project named “BookStore” in Symfony using the following command.
symfony new BookStore code
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 made a BooksController, next make a view to render the activity.
Step 3: Create a View
How about we make another envelope named "Books" in "application/Resources/sees/" index. Inside the envelope, make a document "author.html.twig" and include the following changes.
<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');
}
}
Starting at now, we have made a fundamental BooksController and the outcome is rendered. You can check the outcome in the program utilizing the URL "http://localhost:8000/books/author".ges.
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”.
Issue the following command to generate “booksdb” database. This step is used to bind the database in Doctrine.
php bin/console doctrine:database:create
In the wake of executing the command, it consequently produces an exhaust "booksdb" database. You can see the following reaction on your screen.
It will produce the following result −
Created database `booksdb` for connection named default
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.
On the off chance that the table name isn't indicated, at that point it will be resolved consequently in light of the name of the element class.
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;
}
}
Subsequent to making elements, you ought to approve the mappings utilizing the following charge.
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 made the Books table, the element is out of adjust. Give us a chance to make the Books table utilizing Symfony order in the subsequent stage.
Teaching can consequently make all the database tables required for Book substance. This should be possible utilizing the accompanying charge.
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.
As found in the Bind an Entity area, the following summon produces all the getters and setters for the Book class.
$ php bin/console doctrine:generate:entities AppBundle/Entity/Book
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));
}
We should make a view that focuses to show activity. Move to the perspectives index and make record "display.html.twig". Include the accompanying changes in the document.
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
How about we make a usefulness to include a book into the framework. Make another page, newAction technique in the BooksController as takes after.
// 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(),));
}
We should make a view that focuses to another activity. Move to the perspectives catalog and make a record "new.html.twig". Include the accompanying changes in the record.
{% 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 −
We should change the newAction technique and incorporate the code to deal with shape accommodation. Additionally, store the book data 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.
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 handling two functionalities. On the off chance that the demand just contains id, at that point we bring it from the database and show it in the book shape. What's more, if the demand contains full book data, at that point we refresh the subtle elements in the database and divert to the book show page.e.
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.
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 contains an arrangement of PHP segments, an application structure, a group and a reasoning. Symfony is greatly adaptable and equipped for meeting every one of the prerequisites of cutting edge clients, experts, and a perfect decision for every one of the learners with PHP.
It's my first contribution in this tutorial.