In this chapter, we will learn how to create a complete MVC based BookStore application in FuelPHP.
Create a new project named “BookStore” in FuelPHP using the following command.
oil create bookstore
Create a new layout for our application. Create a file, layout.php at location fuel/app/views/layout.php. The code is as follows,
<!DOCTYPE html> <html lang = "en"> <head> <meta charset = "utf-8"> <meta http-equiv = "X-UA-Compatible" content = "IE = edge"> <meta name = "viewport" content = "width = device-width, initial-scale = 1"> <title><?php echo $title; ?></title> <!-- Bootstrap core CSS --> <link href = "/assets/css/bootstrap.min.css" rel = "stylesheet"> <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"> </script> <script src = "/assets/js/bootstrap.min.js"></script> </head> <body> <nav class = "navbar navbar-inverse navbar-fixed-top"> <div class = "container"> <div class = "navbar-header"> <button type = "button" class = "navbar-toggle collapsed" datatoggle = "collapse" data-target = "#navbar" aria-expanded = "false" ariacontrols = "navbar"> <span class= "sr-only">Toggle navigation</span> <span class = "icon-bar"></span> <span class = "icon-bar"></span> <span class = "icon-bar"></span> </button> <a class = "navbar-brand" href = "#">FuelPHP Sample</a> </div> <div id = "navbar" class = "collapse navbar-collapse"> <ul class = "nav navbar-nav"> <li class = "active"><a href = "/book/index">Home</a></li> <li><a href = "/book/add">Add book</a></li> </ul> </div><!--/.nav-collapse --> </div> </nav> <div class = "container"> <div class = "starter-template" style = "padding: 50px 0 0 0;"> <?php echo $content; ?> </div> </div><!-- /.container --> </body> </html>
Here, we are using bootstrap template. FuelPHP has first class support for bootstrap templates. We have created two variables, title and content. title is used to specify the current page's title and content is used to specify the current page details.
Create a new controller, Controller_Book to show, add, edit, and delete the book. Create a new file, fuel/app/classes/controller/book.php and place the following code.
<?php class Controller_Book extends Controller_Template { public $template = 'layout'; public function action_index() { // Create the view object $view = View::forge('book/index'); // set the template variables $this->template->title = "Book index page"; $this->template->content = $view; } }
Here, we have created the book controller by inheriting template controller and set the default template as fuel/app/views/layout.php.
Create a folder, book in views directory under fuel/app/views folder. Then, create a file index.php inside the book folder and add the following code,
<h3>index page</h3>
As of now, we have created a basic book controller.
Update the default route to set the home page of the application to book controller. Open the default routing configuration file, fuel/app/config/routes.php and change it as follows.
<?php return array ( '_root_' => 'book/index', // The default route '_404_' => 'welcome/404', // The main 404 route 'hello(/:name)?' => array('welcome/hello', 'name' => 'hello'), );
Now, requesting the URL, http://localhost:8080/ will return the index page of the book controller as follows,
Create a new database in MySQL server, using the following command,
create database howcodex_bookdb
Then, create a table inside the database using the following command,
CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(80) NOT NULL, author VARCHAR(80) NOT NULL, price DECIMAL(10, 2) NOT NULL );
Insert some sample record into the table using the following SQL statement.
INSERT INTO book(title, author, price) VALUES( 'The C Programming Language', 'Dennie Ritchie', 25.00 ),( 'The C++ Programming Language', 'Bjarne Stroustrup', 80.00 ),( 'C Primer Plus (5th Edition)', 'Stephen Prata', 45.00 ),('Modern PHP', 'Josh Lockhart', 10.00),( 'Learning PHP, MySQL & JavaScript, 4th Edition', 'Robin Nixon', 30.00 )
Configure the database using database configuration file, db.php located at fuel/app/config.
<?php return array ( 'development' => array ( 'type' => 'mysqli', 'connection' => array ( 'hostname' => 'localhost', 'port' => '3306', 'database' => 'howcodex_bookdb', 'username' => 'root', 'password' => 'password', 'persistent' => false, 'compress' => false, ), 'identifier' => '`', 'table_prefix' => '', 'charset' => 'utf8', 'enable_cache' => true, 'profiling' => false, 'readonly' => false, ), 'production' => array ( 'type' => 'mysqli', 'connection' => array ( 'hostname' => 'localhost', 'port' => '3306', 'database' => 'howcodex_bookdb', 'username' => 'root', 'password' => 'password', 'persistent' => false, 'compress' => false, ), 'identifier' => '`', 'table_prefix' => '', 'charset' => 'utf8', 'enable_cache' => true, 'profiling' => false, 'readonly' => false, ), );
Update the main configuration file to include ORM package. It is located at “fuel/app/config/”.
'always_load' => array ( 'packages' => array ( 'orm' ), ),
Create a book model in book.php located at “fuel/app/classes/model”. It is defined as follows −
<?php class Model_Book extends Orm\Model { protected static $_connection = 'production'; protected static $_table_name = 'book'; protected static $_primary_key = array('id'); protected static $_properties = array ( 'id', 'title' => array ( 'data_type' => 'varchar', 'label' => 'Book title', 'validation' => array ( 'required', 'min_length' => array(3), 'max_length' => array(80) ), 'form' => array ( 'type' => 'text' ), ), 'author' => array ( 'data_type' => 'varchar', 'label' => 'Book author', 'validation' => array ( 'required', ), 'form' => array ( 'type' => 'text' ), ), 'price' => array ( 'data_type' => 'decimal', 'label' => 'Book price', 'validation' => array ( 'required', ), 'form' => array ( 'type' => 'text' ), ), ); protected static $_observers = array('Orm\\Observer_Validation' => array ( 'events' => array('before_save') )); }
Here, we have specified the database details as properties of the model. It has validation details as well.
Update the index action in book controller to list the available books in the database.
<?php class Controller_Book extends Controller_Template { public $template = 'layout'; public function action_index() { // Create the view object $view = View::forge('book/index'); // fetch the book from database and set it to the view $books = Model_Book::find('all'); $view->set('books', $books); // set the template variables $this->template->title = "Book index page"; $this->template->content = $view; } }
Here, we have used the orm to fetch the book details from the database and then passed the book details to views.
Update the view file index.php located at “fuel/app/views/book”. The complete updated code is as follows,
<table class = "table"> <thead> <tr> <th>#</th> <th>Title</th> <th>Author</th> <th>Price</th> <th></th> </tr> </thead> <tbody> <?php foreach($books as $book) { ?> <tr> <td><?php echo $book['id']; ?></td> <td><?php echo $book['title']; ?></td> <td><?php echo $book['author']; ?></td> <td><?php echo $book['price']; ?></td> <td> <a href = "/book/edit/<?php echo $book['id']; ?>">Edit</a> <a href = "/book/delete/<?php echo $book['id']; ?>">Delete</a> </td> </tr> <?php } ?> </tbody> </table> <ul> </ul>
Now, requesting the URL, http://localhost:8080/ will show the page as follows −
Create the functionality to add a new book into the bookstore. Create a new action, action_add in the book controller as follows,
public function action_add() { // create a new fieldset and add book model $fieldset = Fieldset::forge('book')->add_model('Model_Book'); // get form from fieldset $form = $fieldset->form(); // add submit button to the form $form->add('Submit', '', array('type' => 'submit', 'value' => 'Submit')); // build the form and set the current page as action $formHtml = $fieldset->build(Uri::create('book/add')); $view = View::forge('book/add'); $view->set('form', $formHtml, false); if (Input::param() != array()) { try { $book = Model_Book::forge(); $book->title = Input::param('title'); $book->author = Input::param('author'); $book->price = Input::param('price'); $book->save(); Response::redirect('book'); } catch (Orm\ValidationFailed $e) { $view->set('errors', $e->getMessage(), false); } } $this->template->title = "Book add page"; $this->template->content = $view; }
Here the following two processes are being performed,
Building the book form to add book using Fieldset methods and Book model.
Processing the book form, when the user enters the book information and submitted back the form. It can be found by checking the Input::param() method for any submitted data. Processing the form involves the following steps −
Gather the book information.
Validate the book information. We have already set the validation to be called before save method. If the validation fails, it will throw Orm\ValidationFailed exception.
Store the book information into the database.
Redirect the user to index page on success. Otherwise, show the form again.
We are doing both, showing the form as well as processing the form in the same action. When the user calls the action for the first time, it will show the form. When the user enters the book information and submits the data, then it will process the form.
Create the view for add book action. Create a new file, fuel/app/views/book/add.php and enter the following code,
<style> #form table { width: 90%; } #form table tr { width: 90% } #form table tr td { width: 50% } #form input[type = text], select { width: 100%; padding: 12px 20px; margin: 8px 0; display: inline-block; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } #form input[type = submit] { width: 100%; background-color: #3c3c3c; color: white; padding: 14px 20px; margin: 8px 0; border: none; border-radius: 4px; cursor: pointer; } #form div { border-radius: 5px; background-color: #f2f2f2; padding: 20px; } </style> <div id = "form"> <h2>Book form</h2> <?php if(isset($errors)) { echo $errors; } echo $form; ?> </div>
Here, we are just showing the form created in the action method. In addition, we are showing the errors, if any.
Requesting the url, http://localhost:8080/book/add or clicking the Add book navigation link, will show the form as follows,
After entering the book information and submitting the page, the book information will be stored into the database and the page gets redirected to index page as follows.
Create the functionality to edit and update the existing book information. Create a new action, action_edit in the book controller as follows.
public function action_edit($id = false) { if(!($book = Model_Book::find($id))) { throw new HttpNotFoundException(); } // create a new fieldset and add book model $fieldset = Fieldset::forge('book')->add_model('Model_Book'); $fieldset->populate($book); // get form from fieldset $form = $fieldset->form(); // add submit button to the form $form->add('Submit', '', array('type' => 'submit', 'value' => 'Submit')); // build the form and set the current page as action $formHtml = $fieldset->build(Uri::create('book/edit/' . $id)); $view = View::forge('book/add'); $view->set('form', $formHtml, false); if (Input::param() != array()) { try { $book->title = Input::param('title'); $book->author = Input::param('author'); $book->price = Input::param('price'); $book->save(); Response::redirect('book'); } catch (Orm\ValidationFailed $e) { $view->set('errors', $e->getMessage(), false); } } $this->template->title = "Book edit page"; $this->template->content = $view; }
It is similar to add action, except it searches the requested book by id before processing the page. If any book information is found in the database, it will proceed and show the book information in the form. Otherwise, it will throw file not found exception and exit.
Create the view for edit book action. Here, we are using the same view used for add action.
Click the edit link of any book in the book listing page, it will show the corresponding book form as follows −
Create the functionality to delete book from the bookstore. Create a new action, action_delete in the book controller as follows,
public function action_delete($id = null) { if ( ! ($book = Model_Book::find($id))) { throw new HttpNotFoundException(); } else { $book->delete(); } Response::redirect('book'); }
Here, we are checking for the existence of book in the database using the supplied book id. If the book is found, then it is deleted and redirected to index page. Otherwise, a page not found information will be shown.
Check the delete action by clicking the delete link in the book listing page. It will delete the requested book and then again be redirected to the index page.
Finally, all the functionalities to add, edit, delete, and list the book information is created.
FuelPHP is simple, flexible, scalable, and easily configurable compared to other MVC based PHP frameworks. It provides all the features of the modern MVC framework. It can be used as is or can be changed completely to suit our needs. Above all, it is a great choice for web development.