Introduction to Laravel Framework
This book is about Laravel, a web application development framework that saves you time and effort and makes web development a joy. Laravel has shaken up the PHP community in a big way - especially when you consider that version 1.0 of Laravel was only a couple of years ago. It has been generating a lot of buzz with the promise of making web applications fast and simple to create. Using Laravel, you can build and maintain high-quality web applications with minimal fuss.
Certain parts of a web application development process can be a repetitive, boring task. Laravel lets you focus on the fun stuff - the crux of your web app - while easing the pain of the repetitive bits. In doing so, it provides high-level abstractions of common web development patterns, convenient shortcuts for frequent programming tasks, and clear conventions for how to solve problems.
What Is a Web Framework?
Laravel is a prominent member of a new generation of web frameworks - but what does that term mean, precisely?
Basically, a web framework makes it easier for you to develop your application. Most sites have a common set of functionality (like handling sessions, data validation, etc) and a framework is something that prevents you from re-writing this each time you create a website.
Let’s dive in with a quick example that demonstrates the difference between the previous approach and a web framework’s approach.
We will build a very simple guestbook application using plain vanilla PHP without a framework. We’ll create a new MySql database named “guestbook” and create the “entries” table:
CREATE TABLE `entries` (
`id` INT NOT NULL AUTO_INCREMENT,`username` VARCHAR(50) NOT NULL,`email` VARCHAR(100) NOT NULL,`comment` TEXT NOT NULL,`date_added` DATETIME NOT NULL,PRIMARY KEY(`id`));
On to the PHP stuff. Below is the entire source code of the guestbook script:
<?php
$db_host = "localhost";$db_database = "guestbook";$db_user = "Your_Database_Username";$db_pass = "Your_Database_Password";// connect to database$db_conn = mysql_connect($db_host, $db_user, $db_pass);mysql_select_db($db_database, $db_conn);$gb_entries = ""; // the string we'll append entries to// if form is submitted, then insert into databaseif (!empty($_POST["submit"])) {$username = $_POST["frmName"];$email = $_POST["frmEmail"];$comment = $_POST["frmComment"];$date = Date("Y-m-d h:i:s");$sql_insert = "INSERT INTO entries(username, email, comment, date_added) VALUES('$username', '$email', '$comment', '$date')";mysql_query($sql_insert);$num_rows = mysql_affected_rows();// See if insert was successful or notif ($num_rows > 0) {$ret_str = "Your guestbook entry was successfully added.";} else {$ret_str = "Your guestbook entry was NOT successfully added.";}// append success/failure message$gb_entries .= "<p>$ret_str</p><br />";}$sel_select = "SELECT username, email, comment, DATE_FORMAT(date_added, '%m-%d-%y %H:%i') date_added FROM entries";$result = mysql_query($sel_select);while ($get_row = mysql_fetch_array($result, MYSQL_ASSOC)) {$username = $get_row["username"];$email = $get_row["email"];$comment = $get_row["comment"];$date = $get_row["date_added"];$gb_entries .= "<p>$comment</p><p>Posted on $date by <a href=\"mailto:$email\">$username</a><hr />";}// cleanupmysql_free_result($result);mysql_close($db_conn);?><HTML><HEAD><TITLE>Php Guestbook</TITLE></HEAD><BODY><? echo $gb_entries; ?><form action="<?php echo $PHP_SELF;?>" method="POST"><table border="0"><tr><td>Name</td><td><input type="text" name="frmName" value="" size="30" maxlength="50"></td></tr><tr><td>Email</td><td><input type="text" name="frmEmail" value="" size="30" maxlength="100"></td></tr><tr><td>Comment</td><td><textarea name="frmComment" rows="5" cols="30"></textarea></td></tr><tr><td></td><td><input type="submit" name="submit" value="submit"><input type="reset" name="reset" value="reset"></td></tr></table></form></BODY></HTML>
The guestbook application is ridiculously simple - it will display a form, collect some information from visitors and display the comments posted by them.
Here’s our guestbook app in action:
This PHP script combines all the logic and markup in a single file. This is not necessarily a best practice or modern programming technique in PHP, but it should be straightforward enough for any PHP developer to understand. With a single-page simple web app like this one, the write-it-from-scratch approach isn’t necessarily bad. For one thing, this code is simple to comprehend - even a novice developer can read and understand it fairly easily. But despite its simplicity, this approach has a number of problems and annoyances.
Ask yourself these questions:
- What happens when multiple parts of your application need to interact with the database? Surely that database-related code shouldn’t need to be duplicated in each and every PHP script. The prudent thing to do would be to refactor all database code into a shared PHP file.
- Should a developer really need to worry about opening and closing database connections, learn all the different data-access APIs for multiple database engines and memorize many different SQL dialects? This sort of boilerplate reduces programmer productivity, increases development time and introduces opportunities for bugs. The database-related tasks would best be handled by some database-agnostic, higher-level infrastructure that shields the developer from nitty-gritty of the underlying database implementation.
- What happens when your web app is deployed in multiple heterogenous environments, each with a separate database and credentials? At this point, some environment-specific configuration becomes essential.
- What happens when you develop your app using the MySql database, but your client wants to use PostgreSql instead? Should you go back and change all the
mysql_*
data-access APIs and SQL queries? The pragmatic thing would be to develop the application using database-agnostic libraries such the PDO. But that still doesn’t protect you from rewriting at least some of the SQL DDL and/or DDL queries. - What happens when a HTML/CSS/Javascript designer who has no experience coding PHP wishes to redesign the page? Altering the files in wrong places could crash your entire application. Ideally, the business logic of the web app as well as the database-related code should be separate from the HTML view, so that a designer could edit the latter without affecting the former.
These problems are precisely what a web development framework intends to solve. A web framework provides a programming infrastructure for your applications, so that you can focus on writing clean, maintainable code without having to reinvent the wheel. That’s exactly what Laravel does!
Let’s re-build the guestbook app from scratch using the Laravel framework. We will create a new database named “laravel_guestbook”.
I’ll assume you have Laravel installed in your local machine (installation of the Laravel framework will be discussed in a later lesson). Next open up the
database.php
file in the app/config
directory of your Laravel application. Make sure that the default
key is set to mysql
:return array(
...'default' => 'mysql',
Then enter your database information:
...
'connections' => array('mysql' => array('driver' => 'mysql','host' => '127.0.0.1','database' => 'laravel_guestbook','username' => 'Your_Database_Username','password' => 'Your_Database_Password','charset' => 'utf8','collation' => 'utf8_unicode_ci','prefix' => '',),...
It’s good practice to use migrations to track the changes in the database. You may think of Laravel migrations as version control for your databases. In order to use migrations, you first have to allow Laravel to create a special table in your database (this table is used by Laravel internally to to track the migrations that are executed).
We will use the Laravel Artisan command-line utility to install migrations in our database. Open a terminal at the root folder of your laravel application and execute the following command:
$ php artisan migrate:install
Nice! Now we're ready to do some migrating!
Once that’s done we’ll create the migration file that will create our
entries
table:$ php artisan migrate:make create_entries_table
Migration created successfully!
Laravel will generate a new migration file (mine is named
2013_01_04_103348_create_entries_table.php
) in theapp\database\migrations
folder. Let’s edit this file and define the schema for our entries
table:<?php
use Illuminate\Database\Migrations\Migration;class CreateEntriesTable extends Migration {/*** Run the migrations.*/public function up(){Schema::create('entries', function($t) {$t->increments('id');$t->string('username', 50);$t->string('email', 100);$t->text('comment');$t->timestamps();});/**}* Reverse the migrations.*/public function down(){Schema::drop('entries');}}
The
up()
method contains what you want to do to the database when you execute the migration. It will normally contain an array of column definitions to be created on the table. In our case, it contains the schema for our entries
table. The down()
method will contain what you want to do when you rollback or “undo” the migration.
Let’s switch to the terminal and execute the migration to actually create the table in the database:
$ php artisan migrate
Migrated: 2013_01_04_103348_create_entries_table
If you check your database, you’ll find Laravel has created the
entries
table for us:CREATE TABLE `entries` (
`id` INT(11) NOT NULL AUTO_INCREMENT,`username` VARCHAR(50) NOT NULL,`email` VARCHAR(100) NOT NULL,`comment` TEXT NOT NULL,`created_at` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',`updated_at` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',PRIMARY KEY (`id`));
Now we will create a Laravel data model class that represents the table described above. Our database table is called “entries”, so we will call our model class “Entry”. Let’s create a new PHP file
app/models/Entry.php
and paste the following code:<?php
class Entry extends Eloquent {/*** The database table used by the model.*/* * @var stringprotected $table = 'entries';}
Taking a look at this file shows there isn’t much there. However, the functionality of our
Entry
class is slightly deceiving, because this model inherits all the functionality built into the Laravel Eloquent
class. Your Entry
model controls everything that goes in and out of the entries
table we created. The Eloquent
parent class that Entry
inherits from is a high-level database abstraction layer. This layer is known as an “object relational mapper” because it maps each model directly to a database table.
Let’s give this application a face by creating the view template file. In Laravel, all template files are stored in the
app/views
folder. Laravel comes equipped with its own templating engine called the Blade templating engine. Blade templates files have the extension .blade.php
. Let’s create a new file named home.blade.php
in the app/views
folder:<HTML>
<HEAD><TITLE>Laravel Guestbook</TITLE></HEAD><BODY>@foreach($entries as $entry)<p>{{ $entry->comment }}</p><p>Posted on {{ $entry->created_at->format('M jS, Y') }} by<a href="mailto:{{ $entry->email }}">{{ $entry->username}}</a></p><hr />@endforeach<form action="/" method="POST"><table border="0"><tr><td>Name</td><td><input type="text" name="frmName" value="" size="30" maxlength="50"></td></tr><tr><td>Email</td><td><input type="text" name="frmEmail" value="" size="30" maxlength="100"></td></tr><tr><td>Comment</td><td><textarea name="frmComment" rows="5" cols="30"></textarea></td></tr><tr><td></td><td><input type="submit" name="submit" value="submit"><input type="reset" name="reset" value="reset"></td></tr></table></form></BODY></HTML>
This is essentially the same HTML code we wrote earlier in the plain PHP version. The only difference is that, here we’re using Laravel Blade template syntax e.g.
@foreach($entries as $entry)
. As you may have guessed, @foreach
is just like the foreach
operator that we use in plain PHP to iterate over an array. In this case we’re iterating through all the guestbook entries in the database. {{ $entry->comment }}
is the Blade syntax for PHP’s echo
keyword. In this example, {{ $entry->comment }}
is literally translated into <?php echo $entry->comment; ?>
Of course all the data that we are iterating through aren’t directly available in the view, we will have to pass the data to the view using the controller which will render this view. And that’s what were going to do next.
Let’s create a controller class to handle the business logic of our guestbook app. Since the primary responsibility of this controller is to store and retrieve records from the
entries
table, we’ll name it EntriesController
. Laravel requires that you place all your controller classes in the app/controllers
folder. Let’s create a new file namedapp/controllers/EntriesController.php
and paste the following skeleton code:<?php
class EntriesController extends BaseController {# Handles "GET /" requestpublic function getIndex(){}# Handles "POST /" requestpublic function postIndex(){}}
Controllers in Laravel usually descend from the
BaseController
super-class. By convention, controller method names in Laravel have the following syntax:Name of the HTTP verb (in lowercase) + Name of the action (in Pascal-case)
For instance, if we want to handle the request
GET /page
, our controller method will be named getPage()
. Likewise, if we wanted to handle POST /email
and PUT /file
our controller methods will named postEmail()
and putFile()
respectively.
Returning to our guestbook sample app, we want our controllers to respond to
GET /
and POST /
requests; in other words, we wish to handle reqests for the “index” page. Therefore, we have named our controller methods getIndex()
and postIndex()
respectively.
Let’s first implement the controller for the HTTP
GET /
request:public function getIndex(){
return View::make('home')->with('entries', Entry::all());}
The above code snippet loads a view template named “home” and passes a variable named
$entries
to the template. Laravel automatically maps the “home” view to the app/views/home.blade.php
template file. The $entries
variable contains all rows from our entries
database table. Recall that the table is represented by our Entry
model class; theEntry::all()
method retrieves all records from the database table it represents. Laravel then transforms the “home” template to a fully functional HTML web page and returns it to the user’s browser.
Now that we have a functioning HTML form, let’s implement the
POST /
controller:public function postIndex(){
// get form input data$entry = array('username' => Input::get('frmName'),'email' => Input::get('frmEmail'),'comment' => Input::get('frmComment'),);// save the guestbook entry to the databaseEntry::create($entry);return Redirect::to('/');}
We’ll step through each segment of the code:
$entry = array(
'username' => Input::get('frmName'),'email' => Input::get('frmEmail'),'comment' => Input::get('frmComment'),);
Inside the method, we first have to get what the user has inputted in the HTML form. Laravel allows as to do that using the
Input::get('form_field_name')
method where the form_field_name is the name of the input field. For instance, we have an input field named “frmName” in our HTML form: <input type="text" name="frmName" />
. TheInput::get('frmName')
method will return whatever data the user had entered in that textbox. In the above snippet, we gather all relevant form data into the $entry
array. Take note that the array keys above exactly match the column-names of our entries
table.Entry::create($entry);
Inserting Eloquent models into your tables couldn’t be easier. We call the
Eloquent::create()
method which will insert a new record into the database for us - this method will extract the column-names from the associative array and automatically populate all database columns. Contrast the above line of code with the tedious SQL query and the multiple MySql API methods we had to write in our previous plain PHP guestbook app.return Redirect::to('/');
After all work is done, we return a HTTP 302 redirect response to send the user back to our homepage; essentially, we’re transferring the request to the
getIndex()
controller.
Here’s the
app/controllers/EntriesController.php
file in its entirety:<?php
class EntriesController extends BaseController {public function getIndex(){return View::make('home')->with('entries', Entry::all());}public function postIndex(){// get form input data$entry = array('username' => Input::get('frmName'),'email' => Input::get('frmEmail'),'comment' => Input::get('frmComment'),);// save the guestbook entry to the databaseEntry::create($entry);return Redirect::to('/');}}
We’re almost done with our application. We must let Laravel know about our
EntriesController
. Let’s open up the file app/routes.php
and register our controller class by pasting the following code:<?php
Route::controller('EntriesController', '/');
Here, we register our controller with the index URL (“/”).
It’s a good idea to generate PHP autoload files at this stage. We will use the
composer
command-line utility to do that:$ composer dump-autoload
That’s it! We have just created our first Laravel application. Here’s the Laravel-powered guestbook app in it’s full glory:
Again, don’t worry too much about the details; just get a feel for the overall design of the app. The primary thing to note in the Laravel-powered application is the separation of concerns:
- Our database table is now represented by a PHP class. This class is called a “model”. Using it, you can create, retrieve, update and delete records (“CRUD”) in your database using simple PHP methods rather than writing tedious SQL statements.
- The
EntriesController
controller specifies which response is returned for a given URL pattern. In our case, the HTTPGET /
request will be handled by thegetIndex()
method, and HTTPPOST /
request will be handled by thepostIndex()
controller. Our application logic is contained within these two controllers. - The
app/views/home.blade.php
file is an HTML view template that describes the design of the page. It uses the Laravel Blade template language with basic logic statements - e.g.,@foreach($entries as $entry)
Taken together, these pieces loosely follow a design pattern called Model-View-Controller (MVC). Simply put, MVC is way of developing software so that the code for defining and accessing data (the model) is separate from request-routing logic (the controller), which in turn is separate from the user interface (the view). (We shall discuss MVC in more depth in a later chapter.)
A key advantage of such an approach is that components are loosely coupled. Each distinct piece of a Laravel web application has a single key purpose and can be changed independently without affecting the other pieces. For instance:
- a developer can change the URL for a given part of the application without affecting the underlying implementation.
- a designer can change a page’s HTML without having to touch the PHP code that renders it.
- a database administrator can rename a database table and specify the change in a single location, rather than having to search and replace through dozens of files.
If all this code were interspersed through a single HTML-PHP hybrid file that contained the HTML view as well as all the model and controller (routing) data, it would not be nearly as manageable and maintainable. Design patterns such as MVC are created to make a developer’s life easier. This is where web frameworks like Laravel score over plain PHP.
The Laravel Advantage
Laravel embraces a general development philosophy that sets a high priority on creating maintainable code. By following some simple guidelines, you should be able to keep a rapid pace of development and be free to change your code with little fear of breaking existing functionality. Laravel achieves this by adopting several proven web development patterns and best practices.
Single Responsibility Pattern
The Laravel MVC architecture is great from a developer’s perspective because it separates each component of a web application into an isolated code base that is easily managed without having to worry about breaking other parts of your application.
Convention over configuration
Laravel defines the directory structure of your application for you and sets a series of conventions for naming files, classes, and database tables. It takes advantage of these conventions to tie together your application without a lot of configuration. You may initially be concerned about the idea of Laravel telling you how to structure your application. Worry not! You’ll quickly notice that not having to make these judgements yourself actually speeds up development time and creates a more consistent code base between different teams members and projects. By choosing smart defaults, Laravel allows you to focus on the functionality of your application and develop powerful web applications quickly, with code that is clean and easy to maintain.
Don’t-Repeat-Yourself (DRY)
Laravel promotes the DRY principle. Functionality is written cleanly once, and only once. Laravel provides an environment that makes it easy to consolidate shared code between different components of your application.
Unit testing
Laravel gives much importance to testing. Writing code is always done in parallel with tests to ensure the code works as intended and will continue to work when things around it change.
Comments
Post a Comment