← Back to the Blog

Developing application with Laravel 5 - Part 1

By Sid Young
Developing application with Laravel 5 - Part 1

Laravel is a PHP framework that has been taking the PHP development world by storm, its one of the most "Starred" repositories on GitHub and it has a huge and growing worldwide community, all this in just four years. One of the primary reasons is the use of the best quality features from other frameworks that enables you to rapidly build and deploy working cloud based applications.

For this series of articles we will use a CentOS 7 virtual instance to get started with developing a Laravel application. The latest version of Laravel at time of writing is 5.2 and the virtual instance of CentOS has PHP 7 from the Remi repository.

Installing composer and Laravel.

Laravel uses Composer to instal its packages, it works nicely and if you have never used composer you will pick it up easily and quickly. Installing Composer is well documented on the Internet, in brief, you can instal it simply using:

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

Once Composer has installed, you can instal the latest Laravel 5.2 distribution using:

composer global require "laravel/installer"

Once Laravel itself is installed (via Composer), you can create a project and then configure the project's environment as required prior to coding your application.

To create your new project, change to the directory below where you want the project to live, in this case the web server instance runs out of /var/www/vhosts/<my-domain-name.com/httpdocs

Under the httpdocs directory is where I want my project directory, so we now execute the command:

composer create-project --prefer-dist laravel/laravel testapp

The screen output is very verbose, but you will see looks something like...
 

Installing laravel/laravel (v5.2.15)
  - Installing laravel/laravel (v5.2.15)
    Downloading: 100%         

Created project in testapp
> php -r "copy('.env.example', '.env');"
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing vlucas/phpdotenv (v2.2.0)
    Downloading: 100%         

  - Installing symfony/polyfill-mbstring (v1.1.0)
    Downloading: 100%         

.............

laravel/framework suggests installing pusher/pusher-php-server (Required to use the Pusher broadcast driver (~2.0).)
sebastian/global-state suggests installing ext-uopz (*)
phpdocumentor/reflection-docblock suggests installing dflydev/markdown (~1.0)
phpdocumentor/reflection-docblock suggests installing erusev/parsedown (~1.0)
phpunit/phpunit-mock-objects suggests installing ext-soap (*)
phpunit/php-code-coverage suggests installing ext-xdebug (>=2.2.1)
phpunit/phpunit suggests installing phpunit/php-invoker (~1.1)
Writing lock file
Generating autoload files
> php artisan clear-compiled
> php artisan optimize
Generating optimized class loader
> php artisan key:generate
Application key [VjgczPCWaIV8WzOqUPpEUBaW9EW8zWAZ] set successfully.
[root@ws2 laravel]# ls -la
total 40
drwxr-xr-x  6 root root 4096 Feb 18 11:13 .
drwxr-xr-x  5 root root 4096 Feb  9 14:43 ..
drwxr-xr-x 11 root root 4096 Feb 18 11:17 testapp

 

Our framework is now installed and we can now begin the next step. For any useable project you will need to access a database, this will require the Laravel environment to be configured, for simplicity a file called .env exists in the "testapp" directory that holds the key parameters for accessing a database.

Change into the testapp directory and open up the .env file with your favourite editor, I use vi.

cd testapp
vi .env

The file contains the following:

APP_ENV=local
APP_DEBUG=true
APP_KEY=VjgczPCWaIV8WzOqUPpEUBaW9EW8zWAZ

DB_HOST=127.0.0.1
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

The default database values are for "homestead", configure these to use you own database, it is assumed you know how to do this. For our example, I am going to use a database called "test", with a "test" user and "test" password as a pure example and not for any type of external production deployment. It is highly advised you use a strong username/password combination for you database configuration for any production systems and for any Internet connected development servers.

The last thing to do is set the permissions of the files and directories, they need to be accessible as the web server user, in our case "apache" and writeable where needed (storage and logs).

root@ws1 testapp#find . -type f -exec chown apache:apache {} \; -print
root@ws1 testapp#find . -type d -exec chown apache:apache {} \; -print
root@ws1 testapp#find . -type f -name "*.php" -exec chmod 644 {} \; -print

Our Test Application

For this example, we are going to create a few database tables, some Models to manipulate them and a simple View to show the table contents prior to diving into the full Model View Controller (MVC) design cycle that Laravel is designed to provide. With a default instal of Laravel 5.2 we have a basic working empty framework that should render in a web browser, to achieve this we need our hosting to point to the testapp/public directory. 

Configure a virtual host entry that looks similar to the file below. I keep all my vhost config files in /etc/httpd/vhost.d, there is one file for each web site, your hosting plan might be preconfigured to just httpdocs, you might need to discuss this with your hosting provider.

<VirtualHost *:80>
    ServerName testapp.mydomain.com
    ServerAdmin webmaster@localhost.com
    DocumentRoot /var/www/vhosts/mydomain.com/httpdocs/testapp/public
    <Directory /var/www/vhosts/mydomain.com/httpdocs/testapp/public>
        AllowOverride All
    </Directory>
</VirtualHost>

After the file is configured, a reload of the web server will be required, with a DNS entry in place, we can navigate to testapp.mydomain.com and up comes the Laravel framework's default welcome page. The key point to note is the "public" directory is where your application runs from at all times, so any file references for CSS or Javascript code will be loaded from the public directory and below it.

 

Database Tables

Laravel provides a simple, clean and manageable solution to creating, extending and managing database tables, its called migrations. The migration files live in testapp/database/migrations.

Rather than raw SQL definition files as used by old school project development, the migration files are PHP programs that get run to create and or alter DB tables. By default two tables files are created during the instal of the project, one is called users, the other is called password_resets. You will also see the format of the file names, its designed that way to enable the code to manage both the order of the table builds as well as tracking what has been built.

To create the database tables there is a PHP program called "artisan" that lives in your projects home directory, this php application has many uses and automates a lot of the project build process which is another reason Laravel is so popular. The artisan application will build any required directories for some commands and assist in making sure you don't damage your project as you develop.

Lets look at the default table files:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password', 60);
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('users');
    }
}

The basic functions are up() and down() wrapped inside a class called CreateUsersTable. The Class name is embedded in the file name so the artisan tool can create an instance of the class from the file name and the run the up() method to perform the table creation.

I'm not overly happy with this table for my use, so I am going to change it and build the newer version:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration {

public $timestamps = false;

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('usr_first_name');
            $table->string('usr_last_name');
            $table->string('usr_email')->unique();
            $table->string('usr_type')->default('CL');
            $table->string('usr_status')->default('A');
            $table->integer('usr_assigned')->default(0);
            $table->string('usr_pwd', 255);
            $table->date('usr_join_date')->default("0000-00-00")->index('usr_join_date_idx');
            $table->date('usr_last_access_date')->default("0000-00-00");
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('users');
    }
}
~ 

Lets create these tables to show the migration at work and then craft some new ones.

[root@ws2 testapp]# php artisan migrate
Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table
[root@ws2 testapp]#

The output shows the tables are now created as well as the "migrations" table used by artisan to track what has been built.

We can verify the build by running the mysql command line utility and running the "describe" command, as shown next:

MariaDB [testapp]> desc users;
+----------------------+------------------+------+-----+------------+----------------+
| Field                | Type             | Null | Key | Default    | Extra          |
+----------------------+------------------+------+-----+------------+----------------+
| id                   | int(10) unsigned | NO   | PRI | NULL       | auto_increment |
| usr_first_name       | varchar(255)     | NO   |     | NULL       |                |
| usr_last_name        | varchar(255)     | NO   |     | NULL       |                |
| usr_email            | varchar(255)     | NO   | UNI | NULL       |                |
| usr_type             | varchar(255)     | NO   |     | CL         |                |
| usr_status           | varchar(255)     | NO   |     | A          |                |
| usr_assigned         | int(11)          | NO   |     | 0          |                |
| usr_pwd              | varchar(255)     | NO   |     | NULL       |                |
| usr_join_date        | date             | NO   | MUL | 0000-00-00 |                |
| usr_last_access_date | date             | NO   |     | 2016-02-16 |                |
+----------------------+------------------+------+-----+------------+----------------+
10 rows in set (0.00 sec)

In rebuilding the table my way I eliminated the timestamp field and just used dates, added some more details and am now ready to build a model that will manipulate the table and a simple view. I also need to add a route so I can call the view.

Route, Model or View?

Lets start by adding an entry to our routes.php file. This is how Laravel routes URL's to code and it makes building apps very easy, clean and elegant. You will find routes.php in the testapp/app/Http directory.

The contents of an newly created routes.php file is:

<?php

Route::get('/', function () { return view('welcome'); });

Lets add a route for our test app view of the users table. I will be using the bootstrap framework to format up the page and a Laravel blade template to render the output. If you don't know what bootstrap is, take some time to review the link above, in short bootstrap provides a robust responsive environment that simplifies the web GUI significantly. If you are not familiar with Laravel's Blade Templates, don't panic, these will get covered in a future article in this series. 

Normally you would add a route to point to a controller and pass in the method name but for our first example we will just add a route to the view file, this just requires us to open routes.php with an editor and add a GET request line:

Route::get('/users/show', function() { return view('Users.showuser'); });

I also add the following to the end, a "catch all" to show routes I have not yet coded for, you don't need it now but you will find it handy down the track when you are building an app with dozens of routes:

#------------------------------------------------------------
#
# Catch ALL page router
#
Route::any( '{catchall}', function( $page ) { dd( $page.' requested' ); } )->where('catchall', '(.*)');
#
# end of route file

The views are located in testapp/resources/views. You can place sub-directories in here to segment up your app into "modules" and each time you refer to a view, you use the "directory.directory.file" notation. A file in the "view" directory is just a PHP file. Under a Users directory in the testapp/resources/views directory it becomes "Users.filename".

Below is the test file showusers.blade.php with all markup included, this code includes the bootstrap Javascript and CSS as well as the JQuery library needed by bootstrap, its all hosted from content delivery networks so I don't need anything local:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Show Users</title>
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

</head>
<body>
<div class='container'>
    <div class="row">
        <div class="col-lg-12"><h3 class="page-header">Existing Users</h3></div>
    </div>
    <div class="row">
        <div class='col-lg-12'>
        <table  class="table table-hover">
            <thead>
                <tr>
                <th>E-Mail</th>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Status</th>
                <th>Role</th>
                <th>Created</th>
                <th>Last Accessed</th>
                </tr>
            </thead>
            <tbody>
            @foreach($users as $user)
                       <tr>
                            <td>{{ $user->usr_email }}</td>
                            <td>{{ $user->usr_first_name }}</td>
                            <td>{{ $user->usr_last_name }}</td>
                            <td>{{ $user->usr_status }}</td>
                            <td>{{ $user->usr_type }}</td>
                            <td>{{ $user->usr_join_date }}</td>
                            <td>{{ $user->usr_last_access_date }}</td>
                  </tr>
                  @endforeach
             </tbody>
        </table>
            </div>
    </div>
</div>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</body>
</html>

Lets do a quick breakdown of this file:

  • The head section is pretty straight forward, it has components to load for the bootstrap framework, including some Javascript and CSS libraries.
  • The body consists of a 'container' object and two 'row' objects.
  • One 'row' is a page header and the other 'row' is a table which we will populate from our controller.
  • The blade template bits are the {{ $variable }} construction... this will be obvious when we look at the Controller code.

If you try and run this in your web browser you should get some output, using my local server http://testapp.mydomain.com/users/show I get a Laravel Framework error, briefly shown here:

Whoops, looks like something went wrong.

2/2 ErrorException in b318075f96ee7243846c71ec13cf0e23 line 37:Undefined variable: users (View: /var/www/vhosts/mydomain.com/laravel/drs/resources/views/Users/showusers.blade.php)

in b318075f96ee7243846c71ec13cf0e23 line 37
at CompilerEngine->handleViewException(object(ErrorException), '1') in PhpEngine.php line 44

The error is the undefined variable "$users", its not yet been defined anywhere. So this presents a good time to outline Laravel's, MVC design concept as I understand it.

A brief intro to the MVC Concept

MVC is an old software engineering concept that has been used in Frameworks for years, as a result its a mature and well tested architectural design pattern that is often used. There are numerous deviations of MVC but essentially I see it as:

  • Views - Contain all the markup to render the data which is passed in. There should generally be no code to access a data base or make business decision logic. From time to time, some support code to render the output might be needed but this is rare.
  • Models - Contain the code needed to access a database table, no business logic should be present, just basic methods to access data and return it to the caller. Think of it this way, if you have 55 tables then you will have 55 models in most application designs. Models can also be non-database related.
  • Controllers - These contain the business logic that calls the Models to get the data and then manipulates the data for presentation by the View. The Controllers should also handle form posts and if your building other web services then Controllers will do the back end work of those as well.

The MVC concept is simple and works well in the Laravel Framework, I have only just barely touched on the subject but we will now change the routes.php file to include a controller and add more code. This is where the artisan tool comes in handy, lets add a controller called UserController and include some code to render our view.

From the testapp base directory run the artisan script using the following command line:

[root@ws2 testapp]# php artisan make:controller UserController
Controller created successfully.
[root@ws2 testapp]# cd app/Http/Controllers/
[root@ws2 Controllers]# ls
Auth  Controller.php  UserController.php
[root@ws2 Controllers]# ls -la
total 20
drwxr-xr-x 3 apache apache 4096 Feb 18 13:53 .
drwxr-xr-x 5 apache apache 4096 Feb 18 13:20 ..
drwxr-xr-x 2 apache apache 4096 Feb 13 01:05 Auth
-rw-r--r-- 1 apache apache  361 Feb 13 01:05 Controller.php
-rw-r--r-- 1 root   root    182 Feb 18 13:53 UserController.php
[root@ws2 Controllers]#

We now have an empty basic controller, now we can edit our routes.php file again and change the Route for the /users/show URL:

vi routes.php
....
Route::get('/users/show', function() { return view('Users.showusers'); });
changes to:
Route::get('/users/show', 'UserController@ShowUsers');
:wq!

Now we can edit our Controller file located in:

testapp/app/Http/Controllers/UserController.php

To verify the route worked and the method gets called I created the method with a handy dump function:

<?php namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class UserController extends Controller
{
    public function ShowUsers()
    {
        dd($this);
    }
}

If you refresh your web browser you should now get a dump of the controller object:

UserController {#306 ?
  #middleware: []
  #beforeFilters: []
  #afterFilters: []
  #validatesRequestErrorBag: null
}

This shows a few important steps, our route now causes the Framework to create our UserController object, and our ShowUsers() function is being called, the dd() method just dumps the controller object and exits.

If we now change the function ShowUsers() to actually create a user, add it to a container object such as an array and pass this to the view as a "$users" variable, our view can then render the data. Remove the dd($this); line and replace the function with:

public function ShowUsers()
    {
        $user = new \stdClass;
        $user->usr_first_name='fred';
        $user->usr_last_name='smith';
        $user->usr_email='fred@test.com';
        $user->usr_status='A';
        $user->usr_type='USER';
        $user->usr_join_date='2016-01-30';
        $user->usr_last_access_date='2016-02-13';
        $data = array($user);
        return view('Users.showusers',['users'=>$data]);
    }

Now refresh the browser and you should have a working bootstrap responsive table (with row highlighting) of our single user. If we create more "user" objects and add them to the array being passed to the view, then we get those additional rows displaying as well.

So far so good. Now lets build a Model and fetch data from the database. This will exercise a few aspects of the Framework, we will use artisan to create a Model and a database "seeder". The Seeder is a mechanism to populate our database tables with constants that are needed for the application. In our case we need some semi-real data as we don't (yet) have a data entry form.

First the Model, using the Laravel artisan tool to make a Model:

# php artisan make:model Users
Model created successfully.
#ls -la app/
total 48
drwxr-xr-x 10 apache apache 4096 Feb 18 16:04 .
drwxr-xr-x 11 apache apache 4096 Feb 18 12:28 ..
drwxr-xr-x  3 apache apache 4096 Feb 13 01:05 Console
drwxr-xr-x  2 apache apache 4096 Feb 13 01:05 Events
drwxr-xr-x  2 apache apache 4096 Feb 13 01:05 Exceptions
drwxr-xr-x  5 apache apache 4096 Feb 18 15:03 Http
drwxr-xr-x  2 apache apache 4096 Feb 13 01:05 Jobs
drwxr-xr-x  2 apache apache 4096 Feb 13 01:05 Listeners
drwxr-xr-x  2 apache apache 4096 Feb 13 01:05 Policies
drwxr-xr-x  2 apache apache 4096 Feb 13 01:05 Providers
-rw-r--r--  1 apache apache  452 Feb 13 01:05 User.php
-rw-r--r--  1 root   root    101 Feb 18 16:04 Users.php
# 

The 'Model' "Users.php" is created in the testapp/app directory, later I will show you how to put this in a directory called Models under the 'app' directory, just by reconfiguring the environment. For the moment it's current location will suffice. Now lets edit the Model to do a DB table fetch from our "users" table and return that data back to the Controller.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Users extends Model
{
    public function getActiveUsers()
    {
        return \DB::table('users')->where(['usr_status'=>'A'])->get();
    }
}

Now we need to change our controller file so instead of using the fixed data, we create an instance of the 'Model' and call the method to get data from the Database. Open the UserController file and edit the ShowUsers() function to look like:

<?php namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class UserController extends Controller
{
    public function ShowUsers()
    {
        $Users = new \App\Users();
        $data = $Users->getActiveUsers();
        return view('Users.showusers',['users'=>$data]);
    }
}

Refreshing the web browser should now give us an empty table. Why? Well there is no data in it but there are no errors displayed so the Controller, Model and View are working.

Lets seed our table and then wrap up Part 1. Using the artisan tool again in the testapp directory, we will create a 'Seeder':

# php artisan make:seeder UserTableSeeder
Seeder created successfully.
# ls -la database/seeds/
total 16
drwxr-xr-x 2 apache apache 4096 Feb 18 16:29 .
drwxr-xr-x 5 apache apache 4096 Feb 13 01:05 ..
-rw-r--r-- 1 apache apache  240 Feb 13 01:05 DatabaseSeeder.php
-rw-r--r-- 1 apache apache    0 Feb 13 01:05 .gitkeep
-rw-r--r-- 1 root   root    194 Feb 18 16:29 UserTableSeeder.php
#

The basic 'Seeder' file has the following:

<?php

use Illuminate\Database\Seeder;

class Users extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}

There is actually a lot missing from this file, so add in our user, this time we can leave the 'default' fields out as the insert will add those. Using an editor, open the UserTableSeeder.php file located in testapp/database/seeds and add the lines below:

<?php

use App\Users;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model;


class UserTableSeeder extends Seeder
{
    public function run()
    {
        DB::table('users')->delete();
                Model::unguard(); 
               Users::create( array('usr_first_name'=>'sid', 'usr_last_name'=>'young', 'usr_type'=>'USER','usr_email'=>'fred@test.com'));
    }
}

Now if we run the seeder from artisan to cause the population of the database table we should see something?

# php artisan db :seed
#

So now NO output shows, that's easy to solve, by default Seeders are disabled!. We need to enable them by editing a file in the seeds directory. The file is called DatabaseSeeder.php. it should look like this:

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // $this->call(UserTableSeeder::class);
    }
}

Lets un-comment the line and run our seeder again:

# php artisan db:seed
Seeded: UserTableSeeder
#

The table has seeded our user into the users table, and we can now run our web app and see the same output as before, this time the data came from the Database via the Model, it was fetched by our Controller and passed to the View for rendering. 

That's a lot accomplished in one tutorial but it shows a simple easy way to get started with the Laravel Framework.

Part 2 - https://www.conetix.com.au/blog/developing-applications-laravel-5-part-2